使用LINQ扩展关联两个列表

时间:2012-07-17 20:23:51

标签: c# asp.net-mvc linq lambda

我有两个不同对象的列表,一个来自第三方API,另一个来自我的数据库 - 我正在尝试将两者作为关系链接。理想情况下,DBML如何为具有外键(Customer.Orders)的表创建关系具有类似的效果。

来自第三方:

class ApiObject {
    public string ID { get; set; }
    public string Title { get; set; }
    public DateTime CreatedDate { get; set; }
    ... 30 other properties ...
}

从我的数据库:

class DbmlObject {
    public int ID { get; set; }
    public string ApiID { get; set; }
    public string OtherString { get; set; }
}

它们通过ApiObject.ID == DbmlObject.ApiID

相关联

我不想合并它们,也不想将它们加入到某个匿名对象中(并明确列出30多个属性) - 而是将DbmlObject作为ApiObject的链接属性。即:可寻址: apiObject.DbmlObjects.First().OtherString或理想apiObject.DbmlObject.OtherString,因为它是1对1的关系。

在控制器中:

List<ApiObject> apiObjects = _thirdParty.GetObjects();

DbmlDataContext model = new DbmlDataContext();
List<DbmlObject> dbmlObjects = model.GetAllDbmlObjects();

// relate them here

foreach (var apiObject in apiObjects)
    Console.Write(apiObject.DbmlObject.OtherString)
// NOTE: ideally this foreach loop should not make a DBML query on each iteration, just the single GetAllDbmlObjects query above.

1 个答案:

答案 0 :(得分:2)

听起来像join

var combined = from api in apiObjects
               join dbml in dbmlObjects on api.ID equals dbml.ApiID
               select new { api, dbml }

为了在ApiObject中“获取DbmlObject”,您需要继承ApiObject并构造该类的新类,其中包括Dbml属性,创建一个全新的类返回。如果你需要静态输入,这是你能做的最好的 - 当然你可以(误)使用dynamic来获得你想要的东西。

在这种情况下,您提到(在注释中)ApiObject类来自您无法更改的第三方库 - 在这种情况下,我可能会选择创建一个新类型,它接受两个对象的实例在构造函数中并公开您需要的属性 - 装饰器。是的,它看起来像很多代码,但它并不复杂,好的工具会为你自动生成它 - 你得到的代码简洁你需要的类。

如果你想进一步返回IEnumerable<dynamic>,你可以构建一个基于DynamicObject的“组合动态”对象,然后响应ApiObject和DbmlObject的所有属性 - 或者只是添加DbmlObject作为属性。我不是说这是正确的方法,这取决于你需要它 - 记住你正在失去类型安全。这是一个简单的例子:

void Main()
{
    dynamic dyn = new CombiningDynamic(new Foo { X = 3 }, new Bar { Y = 42 });
    Console.WriteLine(dyn.X);
    Console.WriteLine(dyn.Y);
}

public class Foo
{
    public int X {get;set;}
}

public class Bar 
{
    public int Y { get;set;}
}

public class CombiningDynamic : DynamicObject
{
    private object [] innerObjects;


    public CombiningDynamic(params object [] innerObjects) 
    {
        this.innerObjects = innerObjects;

    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        foreach(var instance in innerObjects) 
        {
            Type t = instance.GetType();
            PropertyInfo prop = t.GetProperty(binder.Name);
            if (prop != null && prop.CanRead) 
            {
                result = prop.GetValue(instance, null);
                return true;
            }
        }
        result = null;
        return false;
    }
}

请记住,这是示例代码。如果你真的这么做,你可能想要覆盖更多的方法(TrySetMember,...),你最想定义的是想要缓存反射结果,这样你就不需要每次都走类型了 - 反思是(相对)缓慢。