【问题标题】:Assigning Read Only Property to new object in Entity Framework将只读属性分配给实体框架中的新对象
【发布时间】:2015-04-18 12:50:48
【问题描述】:

我有一个映射到实体框架数据库的对象。这是一个相当大的对象,在获取它们的列表时,我只想要数据的一个子集。

问题是我需要两个只读属性,它们在 TypeId 字段周围有一些重要的逻辑。这是一个例子:

这是我映射到实体的类

public class MyBigObject
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int OwnerId { get; set; }
    public string TypeId { get; set; }
    public bool IsFoo 
    { 
        get { /* complicated logic here for checking if TypeId IsFoo */ }
    }
    public bool IsBar 
    { 
        get { /* complicated logic here for checking if TypeId IsBar */ }
    }

    /* snip about 30 other columns */
}

这一切都很好,而且非常适合提取该对象的列表。但是,随着时间的推移,对象变大了,我想减少 Entity 正在检索的数据量。为此,我们创建了一个未映射到实体的新 DTO 类。

public class MyBigObjectItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string TypeId { get; set; }
    public bool IsFoo { get; set; }
    public bool IsBar { get; set; }
    public bool HasObject1 { get; set; }
    public bool HasObject2 { get; set; }
}

它只是一个非常简单的 getter 和 setter 容器。

然后,对于我的 linq 查询,我有类似的东西

public Task<List<MyBigObjectItem>> GetMyBigObjectItemsAsync(int ownerId, CancellationToken cancellationToken = default(CancellationToken))
{
    return (
        from obj in DataContext.MyBigObject
        join object1 in DataContext.SomeObject1 on obj.Id equals object1.ObjectId into object1items
        join object2 in DataContext.SomeObject2 on obj.Id equals object2.ObjectId into object2items
        where obj.OwnerId = ownerId
        orderby obj.Name
        select new MyBigObjectItem
        {
            Id = obj.Id,
            Name = obj.Name,
            TypeId = obj.TypeId,
            IsFoo = obj.IsFoo,
            IsBar = obj.IsBar,
            HasObject1 = object1items.Any(),
            HasObject2 = object2items.Any()
        }
    ).ToListAsync(cancellationToken);
}

该查询中有很多内容,但我想给出一个准确的例子来说明我在做什么。我们正在加入另外两个我们有一对多关系的对象。我只需要知道是否存在任何关系。

问题在于 Intellitrace 显示错误的 IsFoo = obj.IsFoo,IsBar = obj.IsBar, 行:

LINQ to Entities 不支持指定的类型成员“IsFoo”。仅支持初始化程序、实体成员和实体导航属性。” (System.NotSupportedException)

关于如何完成这项工作的任何想法,或者我注定要获得完整对象的列表,然后将它们转换为我的 DTO?

【问题讨论】:

    标签: c# linq-to-entities entity-framework-6


    【解决方案1】:

    ...还是我注定要获得完整对象的列表,然后将它们转换为我的 DTO?

    差不多。在评估查询之前所做的任何事情都是 Entity Framework 可以转换为 SQL 的,这排除了任何自定义属性,例如您创建的那些。您唯一真正的选择是创建一个存储过程来执行这些属性中包含的逻辑,只返回IsFooIsBar 的结果布尔值,然后使用该SP 来检索您的对象。根据此查询的复杂性,无论如何这可能是一个不错的举措。

    【讨论】:

    • 我最终创建了一个静态扩展类,它接受 TypeId 并返回 IsFoo 和 IsBar 逻辑的结果。那么MyBigObjectMyBigObjectItem都在只读属性中使用静态类,TypeId是从Entity中设置的。
    【解决方案2】:

    您可以使用出色的DelegateDecompiler 库将复杂的属性反编译为它们的实现,然后将其转换为 SQL 代码。您只需使用 NuGet 安装它,然后用它装饰您的属性:

    public class MyBigObject
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int OwnerId { get; set; }
        public string TypeId { get; set; }
        [Computed]
        public bool IsFoo 
        { 
            get { /* complicated logic here for checking if TypeId IsFoo */ }
        }
        [Computed]
        public bool IsBar 
        { 
            get { /* complicated logic here for checking if TypeId IsBar */ }
        }
    
        /* snip about 30 other columns */
    }
    

    然后在 IQueryable 查询上调用 Decompile()

    public Task<List<MyBigObjectItem>> GetMyBigObjectItemsAsync(int ownerId, CancellationToken cancellationToken = default(CancellationToken))
    {
        return (
            from obj in DataContext.MyBigObject
            join object1 in DataContext.SomeObject1 on obj.Id equals object1.ObjectId into object1items
            join object2 in DataContext.SomeObject2 on obj.Id equals object2.ObjectId into object2items
            where obj.OwnerId = ownerId
            orderby obj.Name
            select new MyBigObjectItem
            {
                Id = obj.Id,
                Name = obj.Name,
                TypeId = obj.TypeId,
                IsFoo = obj.IsFoo,
                IsBar = obj.IsBar,
                HasObject1 = object1items.Any(),
                HasObject2 = object2items.Any()
            }
        )
        .Decompile() // Line to add
        .ToListAsync(cancellationToken);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-30
      • 2018-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-01
      • 2021-05-12
      • 2019-04-27
      相关资源
      最近更新 更多