【问题标题】:LINQ navigation property multiple sourcesLINQ 导航属性多个来源
【发布时间】:2015-03-15 13:48:40
【问题描述】:

我有一个存储不同位置的数据库。根据位置的类型,唯一详细信息存储在与常见属性不同的表中(即名称、坐标、描述存储在Locations 表中,而人口存储在CityDetails 表中)。 这些表通过“特定详细信息”表中的 FK 连接。 由于有不止一个“特定详细信息”表,我正在摸索如何查询这些多个表。 我的位置对象如下所示:

[Table("Locations")]
public class LocationData
{
    public Guid Id { get; set; }

    // multiple different properties here.

    public string Type { get; set; }

    public DetailsData { get; set; }
}

基于Type 属性,我可以查看我必须查询的详细信息表。详细信息表至少如下所示:

public abstract class DetailsData 
{
    [Key, ForeignKey("Location")]
    public Guid { get; set; }

    public LocationData Location { get; set; }
}

表示位置类型的每个表都从DetailsData 类继承,并配置为使用“每个具体类的表”继承层次结构。 以下是“特定详细信息”表的示例:

[Table("CityDetails")]
public class CityDetailsData : DetailsData
{
    public string Planet { get; set; }

    public int Population { get; set; }
}

如何在Location 类中填充DetailsData 属性。这是我当前的 LINQ 查询:

from l in Locations
select new
{
    Id = l.Id,
    Name = l.Name,
    Description = l.Description,
    Coordinates = l.Coordinates,
    Type = l.Type,
    DetailsData = CityDetails // Here lies the problem. How can I populate this property properly?
}

【问题讨论】:

  • 我假设您所有的“特定详细信息”表都有不同的列集?
  • 是的。我用一个例子更新了这个问题。

标签: c# sql linq linq-to-entities linq-to-objects


【解决方案1】:

好的,我正在假设您的详细信息表都有不同的列集,您希望能够使用 IEnumerable<LocationData> 实例,并且您希望能够直接访问您返回的任何详细信息表对象的实例。

这是一个顽固的人。基本上有三种方法可以为未知类型的对象编写代码:

  1. 给它一个类型Object
  2. 使所有“详细信息”表都继承自一个通用接口,并使CityDetails 成为实现该接口的对象。
  3. 使用泛型类型,这意味着您最终会指定类型,但您可以将该决定向上推到您实现的类型的声明者。

使用System.Object 意味着您需要将所有DetailsData 对象转换为所需的类型(或使用反射来访问它们的属性),而使用接口意味着您可以直接访问某些属性,但可能不是所有的你想要的。

我认为泛型类型可能是您最好的混合解决方案。

我会这样做:

  1. 接受没有完美的解决方案。
  2. 不要像在示例代码中那样创建匿名类型,而是定义这样的类(类似于 ViewModel,如果您使用的是 ASP.NET MVC):

    public class LocationViewModel<TDetailsData>
    {
        public Guid Id { get; set; }
    
        // multiple different properties here.
    
        public string Type { get; set; }
    
        public TDetailsData DetailsData { get; set; }
    }
    
  3. 定义一个辅助方法,它接受一个类型参数并返回一个TDetailsData 类型的值。使用它来填充 LocationViewModel 上的 DetailsData 属性。

     TDetailsData GetLocationDetails<TDetailsData>(string type, Guid ID)
     {
         // get the appropriate data based on the type.
     }
    
  4. 1234563等,视情况而定。

【讨论】:

  • 查看我更新的问题。每个详细信息表都有一组不同的属性/列,但都继承自同一个抽象类DetailsData。这个抽象类也是主LocationData类中用作属性类型的类的类型。我应该补充一点,这些数据将被转换为稍微不同类型的数据,以用于程序的其他部分。基本上我需要一个 IEnumerable ,其中 LocationData.Details 从不同的详细信息表之一填充。
  • 如果您在使用LocationData 的特定实例时不关心智能感知或轻松访问属性值,您就不能编写一个使用参数type 的辅助方法来检查适当的详细信息表并返回 DetailsData?
  • 不,那时我并不关心智能感知。我的工作流程是这样的: 1. 查询位置表。 2. 查询相应的详细信息表并将其存储在Details 属性中。 3. 将其返回到存储库。 4. 将其传递给转换器 5. 将转换后的数据返回给用户。我会试试你的想法。太简单了,我完全忘记了......
  • @Ruhrpottpatriot 哈哈!我给了你一个过于复杂的答案,因为我想,“问题不可能这么简单!他一定是在要求一些非常微妙的东西!”
  • 大概就是这么简单。问题是:我为服务管理器创建了一个请求来处理(与存储库的工作方式有关,因为它可以根据请求和服务管理器使用多个数据源(即数据库或 webApi))。针对数据库的请求是 Func&lt;TIn, TOut&gt; 表达式。我不确定我是否可以做一些简单的事情,比如方法调用。或者更好:我确信它必须在 LINQ 中完成。好吧,我错过了树木的树林...... lol
【解决方案2】:

如果我理解正确,您希望动态确定类型并即时处理它。在这种情况下,您可以使用dynamic。我没有测试过这段代码,但你可以在这一行思考

        public DetailsData GetDetailsData(Type t) 
        {
            dynamic typVal = new ExpandoObject();

            if(t == typeof(CityDetails))
            {
                typVal = new CityDetails();
            }
            // add other types

            return (DetailsData)PopulateDetailsData(typVal);
        }

        public DetailsData PopulateDetailsData(CityDetails cd)
        {
            cd.Planet = new CityDetails().Planet;
            return cd;
        }

        // Add other type related methods with same 
        // signature with input parameter differentiated by types
        // for example
        public DetailsData PopulateDetailsData(TownDetails td)
        {
            td.Income = new TownDetails().Income;
            return td;
        }

在查询中,你可以有类似下面的东西

from l in Locations
select new
{
    Id = l.Id,
    Name = l.Name,
    Description = l.Description,
    Coordinates = l.Coordinates,
    Type = l.Type,
    DetailsData = GetDetailsData(l.Type)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多