.net - foreign - linq entity framework c#
¿Cómo puedo configurar Entity Framework para recortar automáticamente los valores recuperados para columnas específicas asignadas a campos de caracteres(N)? (4)
Entity Framework no proporciona enlaces para cambiar la forma en que compone las sentencias de SQL, por lo que no puede decirle que extraiga y recorte campos de cadenas de la base de datos.
Sería posible recortar las propiedades de cadena en el evento ObjectContext.ObjectMaterialized
, pero creo que esto afectaría enormemente el rendimiento. Además, se necesitaría mucho código if-else
o switch
para hacer esto para propiedades específicas (como pretende hacer). Pero podría valer la pena intentarlo si desea hacer esto para casi todas las propiedades (excepto las claves, por ejemplo).
De lo contrario, me gustaría ir para las propiedades adicionales.
Estoy trabajando con una base de datos de terceros en la que todos los valores de texto se almacenan como char(n)
. Algunos de estos valores de texto son claves principales, mientras que otros son solo texto normal legible por humanos. Para este último, quiero que los valores recuperados se recorten automáticamente.
Sé que puedo agregar Trim
a todas mis LINQ a las consultas de Entidades, pero esto es confuso, poco confiable e inigualable. Me gustaría configurar Entity Framework para recortar automáticamente los valores recuperados de columnas específicas.
Sin embargo, no sé cómo hacer esto. Estoy usando la API fluida de EF Lo más cercano que he pensado hasta ahora es crear propiedades adicionales para envolver las propiedades reales con las llamadas al método Trim
, pero esto es complicado y aún no es muy fácil de mantener. También preferiría que el recorte se produzca en la base de datos en lugar de la aplicación.
Rowan Miller (gerente de programas para Entity Framework en Microsoft) recientemente publicó una buena solución para esto que utiliza Interceptores. Es cierto que esto solo es válido en EF 6.1+. Su publicación trata sobre cadenas de arrastre en uniones, pero básicamente, la solución aplicada elimina de forma ordenada cadenas de arrastre de todas las propiedades de cadena en sus modelos, de forma automática, sin afectar notablemente el rendimiento.
Publicación original en el blog: solución al problema de los espacios en blanco finales en uniones de cadenas
El código relevante se vuelve a publicar aquí, pero te animo a que leas su publicación en el blog. (También si usas EF, deberías leer su blog de todos modos).
using System.Data.Entity.Core.Common.CommandTrees;
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure.Interception;
using System.Linq;
namespace FixedLengthDemo
{
public class StringTrimmerInterceptor : IDbCommandTreeInterceptor
{
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
{
var queryCommand = interceptionContext.Result as DbQueryCommandTree;
if (queryCommand != null)
{
var newQuery = queryCommand.Query.Accept(new StringTrimmerQueryVisitor());
interceptionContext.Result = new DbQueryCommandTree(
queryCommand.MetadataWorkspace,
queryCommand.DataSpace,
newQuery);
}
}
}
private class StringTrimmerQueryVisitor : DefaultExpressionVisitor
{
private static readonly string[] _typesToTrim = { "nvarchar", "varchar", "char", "nchar" };
public override DbExpression Visit(DbNewInstanceExpression expression)
{
var arguments = expression.Arguments.Select(a =>
{
var propertyArg = a as DbPropertyExpression;
if (propertyArg != null && _typesToTrim.Contains(propertyArg.Property.TypeUsage.EdmType.Name))
{
return EdmFunctions.Trim(a);
}
return a;
});
return DbExpressionBuilder.New(expression.ResultType, arguments);
}
}
}
}
Rowan continúa: "Ahora que tenemos un interceptor, debemos decirle a EF que lo use. Esto se hace mejor a través de la configuración basada en código. Podemos simplemente colocar la siguiente clase en el mismo ensamblado / proyecto que nuestro contexto y EF seleccionará arriba ".
using System.Data.Entity;
namespace FixedLengthDemo
{
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
AddInterceptor(new StringTrimmerInterceptor());
}
}
}
Use propiedades con campos de respaldo en lugar de propiedades automáticas en sus entidades.
Agregue el "Trim ()" en el establecedor de propiedades, así:
protected string _name;
public String Name
{
get { return this._name; }
set { this._name = (value == null ? value : value.Trim()); }
}
Escribí mi propio generador de POCO que solo hace esto automáticamente, pero si no tienes una opción como esa, ReSharper puede agregar campos de respaldo a propiedades automáticas en dos pulsaciones similares. Simplemente hágalo para cadenas, y puede hacer una búsqueda / reemplazo global (en el ámbito del archivo) para " = value;
" con " = value.Trim();
".
Utilicé el enfoque dado por Stuart Grassie, pero al principio no funcionó porque el tipo de columna solo contenía "char", "varchar", etc. Las columnas son en realidad "char (30)", "varchar (10)", ¡Una vez que cambié la línea que sigue funcionó a la perfección!
from: if (propertyArg != null && _typesToTrim.Contains(propertyArg.Property.TypeUsage.EdmType.Name))
a: if (propertyArg != null && _typesToTrim.Any(t => propertyArg.Property.TypeUsage.EdmType.Name.Contains(t)))
Gracias Stuart!