2012-07-17 39 views
1

我有两个不同的对象列表,一个来自第三方API,另一个来自我的数据库 - 我试图将这两个关系链接起来。理想情况下,DBML与外键表(Customer.Orders)创建关系的效果相似。关联两个列表LINQ扩展

来自第三方:

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.DbmlObjects.First().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. 
+0

它们是如何通过“ApiID”关联的? – 2012-07-17 20:25:55

+0

@TimSchmelter by'ApiObject.ID == DbmlObject.ApiID',是我的猜测。 – 2012-07-17 20:27:11

+0

是的,对不起,以为它很直观,但我会明确 – arserbin3 2012-07-17 20:28:36

回答

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,...),并且你最明确地想要缓存反射结果,所以你不需要每次都走这些类型 - 反射(相对)缓慢。

+0

这留给你一个对象: '{ApiObject api,DbmlObject dbml}'而不是'NewObject'的对象..这就是'ApiObject'带有一个额外的子属性'DbmlObject' – arserbin3 2012-07-17 20:31:39

+0

@ arserbin3:那么你需要用'ApiObject' +'OtherString'属性创建第三个类,你可以在'select连接中初始化'。 – 2012-07-17 20:35:02

+0

你可以在ApiObject类中声明'DbmlObject',还是需要保留? – driis 2012-07-17 20:35:06