【发布时间】:2013-11-22 16:40:41
【问题描述】:
一般的想法是从创建一个控件开始,它可以与任何数据库对象一起工作。 数据库通过 LINQ to SQL 访问,数据库对象是从现有数据库自动生成的。
为了使控件与这些对象中的任何一个一起工作,我使用了一个基本接口,所有自动生成的对象都从该接口继承。所以控件实际上可以与该界面一起使用。
这个接口首先应该提供:
- 获取对象标识符(主键)的能力
- 如果通过对象实例编译和调用,则返回此标识符的表达式
所以这看起来像:
public interface IEntity<TEntity, TEntityId>
where TEntity : IEntity<TEntity, TEntityId>
where TEntityId : IEquatable<TEntityId>
{
Expression<Func<TEntity, TEntityId>> GetIdExpression();
TEntityId EntityId { get; }
}
那么数据库对象的类定义如下所示:
//let it be the auto-generated part:
public partial class Entity1
{
public Guid UId { get; set; }
}
//and the manual part:
public partial class Entity1 : IEntity<Entity1, Guid>
{
public Expression<Func<Entity1, Guid>> GetIdExpression()
{
return (Expression<Func<Entity1, Guid>>)(se => se.UId);
}
public Guid EntityId
{
get { return this.UId; }
}
}
我们可以测试一下:
var e1 = new Entity1();
e1.UId = Guid.NewGuid();
Console.WriteLine(e1.UId);
Console.WriteLine(e1.GetIdExpression().Compile()(e1));
这两行的输出是相等的。没关系。
下一个想法是,所有数据库对象的大部分都有int 标识符,名称为Id。最好避免编辑它们中的每一个,即不要编写一个相同的代码来实现IEntity<TEntity, TEntityId>。
就我需要指定这个接口的实现而言,我需要一个类。 现在我结束了
public class IntEntity<TEntity> : IEntity<TEntity, int>
where TEntity : IntEntity<TEntity>
{
public int Id { get; set; }
public Expression<Func<TEntity, int>> GetIdExpression()
{
return (Expression<Func<TEntity, int>>)(e => e.Id);
}
public int EntityId
{
get { return this.Id; }
}
}
然后数据库对象类将从它派生:
//let it be the auto-generated part:
public partial class Entity2
{
public int Id { get; set; }
}
//and the manual part:
public partial class Entity2 : IntEntity<Entity2>
{
}
现在很明显,Entity2 中的Id 确实隐藏了IntEntity<TEntity> 中的Id。同样的测试也证明了这一点:
var re = new Entity2();
re.Id = 5;
Console.WriteLine(re.Id); //5
Console.WriteLine(re.GetIdExpression().Compile()(re)); //0
所以这个解决方案是错误的......
我也尝试将IntEntity<TEntity>抽象化,但显然失败了,因为Entity2Id是在自动生成的部分中定义的,而我无法使其override基础的abstractId类。
我可以做些什么来使所有带有int Id 的数据库对象都使用基类IntEntity<TEntity> 中的Id。或者,可能,反之亦然...
这里的重点是GetIdExpression 返回的表达式应该是e => e.Id 的形式,因为这个表达式稍后会在 LINQ to SQL 查询中使用,所以 LINQ 应该能够将它转换为正确的 SQL 查询.
【问题讨论】:
-
那么为什么您需要
Entity2和IntEntity<Entity2>中的id属性,而不仅仅是其中一个? -
作为求解的变体 - 添加到
Id中的IntEntity<Entity2>关键字virtual和Id中的Entity2override -
@Grundy
IdinEntity2由 LINQ to SQL 自动生成。我无法修改它的声明。 -
@Grundy in
IntEntity<Entity2>我需要Id才能提供IEntity<TEntity, int>的实现。
标签: c# generics inheritance linq-to-sql expression