这是我到目前为止所拥有的
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Text;
namespace Firelight.Business
{
public interface IBaseEntity<K>
{
K Id { get; }
}
/// <summary>
/// Base business database connection object, primary key is int
/// </summary>
/// <typeparam name="T">Table name</typeparam>
public abstract class BaseEntity<T> : BaseEntity<T, Guid> where T : class, IBaseEntity<Guid>
{
}
/// <summary>
/// Base business database connection object
/// </summary>
/// <typeparam name="T">Table name</typeparam>
/// <typeparam name="K">Primary key type</typeparam>
public abstract class BaseEntity<T,K> : IBaseEntity<K> where T : class, IBaseEntity<K>
{
// Avoids having to declare IBaseConnection at partial class level
[Column(Name = "Id", CanBeNull = false, IsPrimaryKey = true, IsDbGenerated = true)]
public K Id { get; set; } // { return default(K); }
public static Table<T> Table
{
get { return LinqUtil.Context.GetTable<T>(); }
}
public static T SearchById(K id)
{
return Table.Single<T>(t => t.Id.Equals(id));
}
public static void DeleteById(K id)
{
Table.DeleteOnSubmit(SearchById(id));
LinqUtil.Context.SubmitChanges();
}
}
}
我的问题是映射不起作用:
数据成员'System.Guid [或System.Int32] Id'的类型 'X' 不是类型映射的一部分 'X'。是上面的成员 继承层次结构的根?
在尝试映射属性之前,我得到了这个:
无法找到密钥的关键成员“Id” 类型'X'上的'Id'。关键可能是错误的 或'X'上的字段或属性 改名。
我尝试将K改为Guid并且它有效,但为什么呢?我不知道泛型输入是一个问题
我不完全确定我实际上也需要接口,我真的不记得为什么我添加了它。
所以,问题是:我怎样才能创作出像这样的作品呢?我想要它所以我可以访问一个通常命名的PK(Id),它总是具有K [Guid或Int32]类型,并重构基本函数,如Id的选择和删除
谢谢!
编辑:
这是有效的
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
namespace Firelight.Business
{
public interface IBaseEntity<K>
{
K Id { get; set; }
}
/// <summary>
/// Base business database connection object
/// </summary>
/// <typeparam name="T">Table name</typeparam>
public abstract class BaseEntity<T> : IBaseEntity<Guid> where T : class, IBaseEntity<Guid>
{
// Avoids having to declare IBaseConnection at partial class level
public Guid Id { get; set; }
public static Table<T> Table
{
get { return LinqUtil.Context.GetTable<T>(); }
}
public static T SearchById(Guid id)
{
return Table.Single<T>(t => t.Id.Equals(id));
}
public static void DeleteById(Guid id)
{
Table.DeleteOnSubmit(SearchById(id));
LinqUtil.Context.SubmitChanges();
}
}
}
我想要的基本相同,用K替换Guid并使类BaseEntity(所以我可以使用相同的类用于Int32和Guid PKs
答案 0 :(得分:8)
您要做的事情不适用于LINQ to SQL。要在LINQ to SQL中使用继承,必须使用基类的[InheritanceMapping]属性。假设您有一个名为Vehicle的基类和一个名为Motorcycle的子类:
[InheritanceMapping(Type = typeof(Motorcycle), IsDefault = true, Code = 1)]
[Table]
public class Vehicle
{
[Column]
public string Make { get; set; }
[Column]
public string Model { get; set; }
[Column(IsDiscriminator = true, Name="VehicleTypeId")]
public VehicleType VehicleType { get; set; }
}
public class Motorcycle : Vehicle
{
// implementation here
}
为了使这个继承在LINQ to SQL中工作,你必须将[InheritanceMapping]
应用于基类和你还必须有一个鉴别器列(例如,VehicleType in上面的例子)。请注意,InheritanceMapping中的代码为“1” - 这意味着如果数据库中的VehicleType为“1”,那么它将创建Motorcycle子类。您在基类上应用了一个[InheritanceMapping]
属性,用于您支持的每个子类。
从纯粹主义的角度来看,这违反了OO,因为基类知道关于它的子类。这种奇怪的做法通常会让人们对LINQ to SQL如何实现继承有所了解。但是你有它。
<强>更新强> 这有效:
public abstract class BaseEntity<T, K> : IBaseEntity<K> where T : class, IBaseEntity<K>
{
public abstract K Id { get; set; }
public static Table<T> Table
{
get { return context.GetTable<T>(); }
}
public static T SearchById(K id)
{
return Table.Single<T>(t => t.Id.Equals(id));
}
public static void DeleteById(K id)
{
Table.DeleteOnSubmit(SearchById(id));
context.SubmitChanges();
}
}
请注意,区别在于我在Id属性上没有任何[Column]
属性。还要注意我把它作为摘要。实现类如下所示:
[Table(Name = "dbo.Contacts")]
public class Contact : BaseEntity<Contact, int>
{
[Column]
public override int Id { get; set; }
[Column]
public string FirstName { get; set; }
[Column]
public string LastName { get; set; }
}
请注意,此类中的Id
属性具有[Column]
属性,并且我正在覆盖抽象的属性。所以我验证了它有效。
话虽如此,我有几个原因可以质疑你当前的设计。首先,您已将数据访问方法作为实体的一部分,许多人(包括我自己)认为这违反了“关注点分离”。您可以在此处引入Repository模式,并为每个实体创建一个存储库 - 根据类型和密钥使该存储库具有通用性。关于上述方法的另一个奇怪之处是BaseEntity
具有Id属性,而子类(在我的示例中为Contact
类)也具有Id属性(以使LINQ To SQL快乐)。必须在基类抽象中创建Id属性,然后在实现者中覆盖它。这违反了DRY,因为我必须为每个实体执行此操作。但这是另一件事,因为你必须跳过这个让LINQ to SQL开心的箍。但它将工作! :)