1

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

来自第三方:

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,因为它是一对一的关系。

在控制器中:

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.
4

1 回答 1

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,...),并且你最明确地想要缓存反射结果,这样你就不需要每次都遍历类型 -反射(比较)慢。

于 2012-07-17T20:28:00.793 回答