不支持实体框架转换

时间:2016-10-08 01:25:22

标签: c# entity-framework

我希望任何人都可以帮助我。我使用EF6和TPC(每个具体类别的表)。有许多表是修订版保存,表示表中的每一行都有相同的ID,但有多个版本。一个版本是当前版本(例如)。 表学生样本:

Id  Version     Name        CurrentVersion
1   1           Murtin      false
1   2           Martin      true
2   1           Reinold     true

我在模型中使用继承。所有模型的基础都是EntityBase

abstract class EntityBase: IEntityBase
{
    [Key]
    [Column(Order = 0)]
    public int Id { get; set; }
}

对于所有修订版本的表,我使用下一个基类

abstract class RevisionBase : EntityBase, IRevisionBase
{
    [Key]
    [Column(Order = 1)]
    public int Version { get; set; }

    [Required]
    public bool CurrentVersion { get; set; }
}

现在我的桌子与我合作,当然是学生

class Student: RevisionBase
{
    [Required]
    public string Name{ get; set; }
}

所以以下代码很简单且有效

new DBContext().Student.FirstOrDefault(s=>s.Id=5 && s.CurrentVersion=true)

对于统一数据处理,我想总是使用相同的基本方法进行加载。所以我有统一的错误处理和日志记录。这个通用的get方法应该总是加载当前版本,如果它是一个版本化的表。

    private TEntity GeneralGet<TEntity>(int id) where TEntity : EntityBase
    {
        using (var ctx = GetContext())
        {
            if (typeof(IRevisionBase).IsAssignableFrom(typeof(TEntity)))
            {
                var allResultsId = ctx.Set<TEntity>().Where(l => l.Id == id);
                var result = allResultsId.ToList().Cast<IRevisionBase>().FirstOrDefault(r => r.CurrentVersion);
                return result as TEntity;
            }
            else        // ansonsten, bei nicht versionierten Objekten
            {
                var result = ctx.Set<TEntity>().FirstOrDefault(l => l.Id == id);
                return result;
            }
        }
    }

这完全正常,但不幸的是我必须加载相同id的所有行并在内存中过滤当前版本。 (ToList加载具有给定id的所有行。)

有没有更好的方法?

我不希望这个“ToList”。我需要的是一个演员来检查我当前的版本,或者混合方法链方式和硬编码的过滤字符串。 (不是很好,但比这更好)我知道这个表有一列CurrentVersion。我想在加载所有记录之前检查一下。

3 个答案:

答案 0 :(得分:2)

EF不像铸造(和一般的接口),C#不允许&#34;铸造&#34;类型。

你问的仍然是可能的。我看到至少有两个(可能不完美,但有效)选项:

(1)创建一个通用约束方法,如下所示:

static IQueryable<TEntity> WhereCurrentVersion<TEntity>(IQueryable<TEntity> source)
    where TEntity : class, IRevisionBase
{
    return source.Where(e => e.CurrentVersion);
}

并通过反射或动态调用它:

private TEntity GeneralGet<TEntity>(int id) where TEntity : EntityBase
{
    using (var ctx = GetContext())
    {
        var result = ctx.Set<TEntity>().Where(e => e.Id == id);
        if (result is IQueryable<IRevisionBase>)
            result = WhereCurrentVersion((dynamic)result);
        return result.FirstOrDefault();
    }
}

(2)动态构建过滤器表达式:

private TEntity GeneralGet<TEntity>(int id) where TEntity : EntityBase
{
    using (var ctx = GetContext())
    {
        var result = ctx.Set<TEntity>().Where(e => e.Id == id);
        if (result is IQueryable<IRevisionBase>)
        {
            var parameter = Expression.Parameter(typeof(TEntity), "e");
            var predicate = Expression.Lambda<Func<TEntity, bool>>(
                Expression.Property(parameter, nameof(IRevisionBase.CurrentVersion)),
                parameter);
            result = result.Where(predicate);
        }
        return result.FirstOrDefault();
    }
}

答案 1 :(得分:0)

您可以创建包含属性的模型,然后您可以使用Cast Extension方法转换为适当的类型。然后做简单的LINQ。

public static T Cast<T>(this Object myobj)
{
    Type objectType = myobj.GetType();
    var dx = myobj.GetType().GetProperties();
    Type target = typeof(T);
    var x = Activator.CreateInstance(target, false);
    var z = from source in objectType.GetMembers().ToList()
            where source.MemberType == MemberTypes.Property
            select source;
    var d = from source in target.GetMembers().ToList()
            where source.MemberType == MemberTypes.Property
            select source;
    List<MemberInfo> members = d.Where(memberInfo => d.Select(c => c.Name).ToList().Contains(memberInfo.Name)).ToList();
    PropertyInfo propertyInfo;
    object value;
    foreach (var memberInfo in members)
    {
        propertyInfo = typeof(T).GetProperty(memberInfo.Name);                
        if (Array.Exists(dx, a => a.Name == propertyInfo.Name))
        {
            value = myobj.GetType().GetProperty(memberInfo.Name).GetValue(myobj, null);
            propertyInfo.SetValue(x, value, null);
        }
    }
    return (T)x;
}

答案 2 :(得分:0)

var tmp = LocalDB.Article.Select(A => A.Matricule).ToArray();

您可以执行类似的操作,在其中将有一个您想要的值的数组,然后您可以使用所需的任何方法或类型将它们添加到另一个数组或列表中...

或者您可以从一开始就做类似的事情

var list = new List<T>();
foreach(var item in LocalDB.Article.Select(A => A.Matricule).ToArray()) 
list.Add(/*Transform item to your wanted type*/);