I think the Entity Framework will not care about the additional columns, as long as they do not
hinder the salvage of entities without additional values.
Adding columns without disrupting Entity
To do this simply set a default value for the additional fields, creating them with the same pure SQL.
You would have to store which additional columns there are. It may even be in the same database,
let's say in a table called ExtraColumns
, which could be read by the Entity Framework and
normally mapped to a ExtraColumn
class.
using (var context = new MyContext())
{
// pegando o ObjectContext
var objectContext = context is DbContext
? ((IObjectContextAdapter)context).ObjectContext
: context as ObjectContext;
var isNullable = false;
var nomeTabela = "Produtos";
var nomeColuna = "NovaColuna"; // NOTA: se essa string vier do usuário então será
// necessário validar o texto para evitar SQL Injection
// Exemplo: permitir apenas letras
if (nomeColuna.Any(ch => !char.IsLetter(ch)))
throw new Exception("Senhor usuário, o nome da coluna permite apenas letras.");
var tipoColuna = "nvarchar(max)";
objectContext.ExecuteStoreCommand(string.Format(@"
ALTER TABLE {0}
ADD [{1}] {2} {3}
CONSTRAINT DEFAULT_{0}_{1} DEFAULT {4}
", nomeTabela, nomeColuna, tipoColuna, isNullable ? "NULL" : "NOT NULL", valorDefault));
var extraColumn = new ExtraColumn
{
NomeTabela = nomeTabela,
NomeColuna = nomeColuna,
TipoColuna = tipoColuna,
}
context.ExtraColumns.Add(extraColumn);
context.SaveChanges();
}
Retrieving values from extra columns
To retrieve values in these additional fields, you can use the
DbContext
or ObjectContext
, but without going through the ORM itself, using the connection itself with
the database and creating a DbCommand
and then a DbDataReader
:
using (var context = new MyContext())
{
// pegando o ObjectContext
var objectContext = context is DbContext
? ((IObjectContextAdapter)context).ObjectContext
: context as ObjectContext;
var nomeTabela = "Produtos";
var extraColumns = context.ExtraColumns
.Where(c => c.NomeTabela == nomeTabela)
.ToList();
var query = "SELECT "
+ string.Join(",", extraColumns.Select(c => c.NomeColuna))
+ " FROM " + nomeTabela;
// pegando a conexão com o DB a partir do ObjectContext
var conn = ((EntityConnection)objectContext.Connection).StoreConnection;
using (var command = conn.CreateCommand())
{
command.CommandText = query;
var reader = command.ExecuteReader();
while (reader.Read())
{
// reader[0] agora contém a primeira coluna extra
// reader[1] agora contém a segunda coluna extra
// ...
}
}
}
Saving values from extra columns
To save values in these additional fields, you can use the ExecuteStoreCommand
method,
as we did before to create the new columns:
using (var context = new MyContext())
{
// pegando o ObjectContext
var objectContext = context is DbContext
? ((IObjectContextAdapter)context).ObjectContext
: context as ObjectContext;
var nomeTabela = "Produtos";
var values = __lista_de_valores_a_atualizar__;
var extraColumns = context.ExtraColumns
.Where(c => c.NomeTabela == nomeTabela)
.ToList();
var queryFmt = "UPDATE "
+ string.Join(",", extraColumns.Select((c, i) => string.Format("{0} = {{{1}}}", c.NomeColuna, i))
+ " FROM " + nomeTabela;
// NOTA: O método abaixo NÃO é suscetível a SQL Injection
objectContext.ExecuteStoreCommand(queryFmt, values.ToArray());
}