我有两个不同对象的列表,一个来自第三方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.
答案 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,...),你最想定义的是想要缓存反射结果,这样你就不需要每次都走类型了 - 反思是(相对)缓慢。