【问题标题】:Genericising one class to handle multiple types泛化一个类来处理多种类型
【发布时间】:2010-10-08 15:51:44
【问题描述】:

我的数据库架构中有一系列大约 30 个查找表,它们都具有相同的布局(我更愿意将它们保留为单独的表而不是一个查找表),因此我的 Linq2SQL 上下文有 30 个实体用于这些查找表。

我有一个标准类,可用于对这 30 个实体中的每一个进行 CRUD 操作,例如:

public class ExampleAttributes : IAttributeList
{
    #region IAttributeList Members

    public bool AddItem(string Item, int SortOrder)
    {
        MyDataContext context = ContextHelper.GetContext();
        ExampleAttribute a = new ExampleAttribute();
        a.Name = Item;
        a.SortOrder = SortOrder;
        context.ExampleAttributes.InsertOnSubmit(a);

        try
        {
            context.SubmitChanges();
            return true;
        }
        catch
        {
            return false;
        }
    }

    public bool DeleteItem(int Id)
    {
        MyDataContext context = ContextHelper.GetContext();

        ExampleAttribute a = (from m in context.ExampleAttributes
                            where m.Id == Id
                            select m).FirstOrDefault();

        if (a == null)
            return true;

        // Make sure nothing is using it
        int Count = (from m in context.Businesses
                             where m.ExampleAttributeId == a.Id
                             select m).Count();

        if (Count > 0)
            return false;

        // Delete the item
        context.ExampleAttributes.DeleteOnSubmit(a);

        try
        {
            context.SubmitChanges();
            return true;
        }
        catch
        {
            return false;
        }
    }

    public bool UpdateItem(int Id, string Item, int SortOrder)
    {
        MyDataContext context = ContextHelper.GetContext();

        ExampleAttribute a = (from m in context.ExampleAttributes
                            where m.Id == Id
                            select m).FirstOrDefault();

        a.Name = Item;
        a.SortOrder = SortOrder;

        try
        {
            context.SubmitChanges();
            return true;
        }
        catch
        {
            return false;
        }
    }

    public String GetItem(int Id)
    {
        MyDataContext context = ContextHelper.GetContext();
        var Attribute = (from a in context.ExampleAttributes
                         where a.Id == Id
                         select a).FirstOrDefault();

        return Attribute.Name;
    }

    public Dictionary<int, string> GetItems()
    {
        Dictionary<int, string> Attributes = new Dictionary<int, string>();

        MyDataContext context = ContextHelper.GetContext();
        context.ObjectTrackingEnabled = false;

        Attributes = (from o in context.ExampleAttributes orderby o.Name select new { o.Id, o.Name }).AsEnumerable().ToDictionary(k => k.Id, v => v.Name);

        return Attributes;
    }

    #endregion
}

我可以复制这个类 30 次,对每个查找实体进行非常小的更改,但这似乎有点混乱 - 所以这个类可以被泛化,所以我也可以将它传递给我想要的类型,并让它在内部处理类型差异在 linq 查询中?这样一来,我就有了一门课要添加,一门课要修复错误等 - 似乎应该这样做。

更新:

下面的安德鲁斯回答给了我一个选项,我在考虑这个问题(传递类型)时真正看到了这个选项,但我需要更多关于如何泛化 linq 查询的说明。谁能澄清一下?

干杯

【问题讨论】:

    标签: c#


    【解决方案1】:

    您可以尝试几件事。

    一种是定义一个接口,其中包含三十个实体类共享的所有相关字段。然后,您可以通过执行类似的操作让每个实体类实现此接口(我们称之为IMyEntity

    public partial class EntityNumber1 : IMyEntity
    {
    }
    

    对于每个实体(其中EntityNumber1 是实体类之一的名称)。当然,这仍然是 30 种不同的定义,但是您的 CRUD 操作类可以在 IMyEntity 上操作,而不必每次都编写一个新类。

    第二种方法是简单地泛化 CRUD 操作类,正如您所建议的那样:

    public class ExampleAttributes<T> : IAttributeList
    {
        ...
    

    这允许您使用 T 作为要操作的类型。当然,这可能与第一种方法结合起来更容易,因为您仍然需要检查属性是否存在并将实体转换为适当的类型或接口。

    编辑:

    要检查实体上是否存在适当的属性,您可能需要使用反射方法。检查给定类型 T 是否具有特定属性的一种方法可能是检查

    typeof(T).GetProperties().OfType<PropertyInfo>().Count<PropertyInfo>(pi => pi.Name == "MyPropertyName" && pi.GetGetMethod().ReturnType == typeof(TypeIWant)) > 0
    

    当然,将TypeIWant 替换为您期望的属性类型,并将MyPropertyName 替换为您正在检查的属性的名称。

    【讨论】:

    • 感谢您的回答,您能更深入地了解第二个选项吗?
    • 嗨 Andrew,感谢您提供额外的细节,不幸的是,它基于给定类型的 linq 泛化,我真的需要澄清 - 我将更新问题,但感谢您的努力。
    【解决方案2】:

    向构造函数添加一个参数来指定类型。然后你可以在内部使用它。一个类,在构造函数中可能有一个 switch 语句。

    【讨论】:

      【解决方案3】:

      对于 LINQ 查询的泛化,最大的问题是您的 DataContext 具有基于类型的集合。有几种方法可以规避这种情况。您可以尝试使用反射来访问它,但这需要相当多的黑客攻击,并且几乎会破坏 LINQ to SQL 提供的所有效率。

      最简单的方法似乎是使用动态 LINQ。我没有亲自使用它,但它似乎应该支持它。您可以在此线程中找到更多信息:Generic LINQ query predicate?http://aspalliance.com/1569_Dynamic_LINQ_Part_1_Using_the_LINQ_Dynamic_Query_Library.1 也许其他人可以提供有关此的更多信息?

      【讨论】:

        【解决方案4】:

        这不一定是问题的答案,但可能是您问题的解决方案。您是否考虑过生成您需要的所有类? T4 内置在 Visual Studio 中,可以为您生成代码。下面的链接对其进行了相当广泛的描述,但包含大量链接以获取更多信息。

        http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx

        这样,您可以在一个地方定义所有方法,并为您的 30 多个查找模型生成类文件。一个地方进行更改等。

        也许值得考虑,如果没有,仍然值得了解。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-12
          • 2020-07-15
          • 1970-01-01
          • 2021-09-11
          相关资源
          最近更新 更多