我正在扩展这个DataContext实体,看起来像这样:
namespace Entities
{
public class User
{
public Int32 Id { get; set; }
public String Username { get; set; }
}
}
..像这样:
public class User : Entities.User
{
new public Int32 Id
{
get { return base.Id; }
}
public void Insert()
{
using (var dc = new DataContext())
{
/*
The "this" keyword should match the type that InsertOnSubmit() expects.
And it does. But I get the following error:
System.NullReferenceException: {"Object reference not set to an instance
of an object."}
*/
dc.Users.InsertOnSubmit(this); // Exception occurs here
dc.SubmitChanges();
}
}
}
我正在使用自定义User类:
var u = new User { Username = "Test" };
u.Insert();
我没有得到的是:我已经实例化了这个类,为什么我得到一个NullReferenceException?
扩展实体类:使用枚举器覆盖属性,同时仍然可以在DataContext实例上的Insert
/ Update
和DeleteOnSubmit
方法上使用“this”关键字
enum AccessLevels
{
Basic,
Administrator
}
namespace Entities
{
public class User
{
public Int32 Id { get; set; }
public String Username { get; set; }
public Int32 AccessLevel { get; set; }
}
}
我如何扩展或改变上面的实体类并实现AcessLevels
枚举器,替换AccessLevel
属性? - 这不会改变实体类的签名,所以我能够在DataContexts上的Insert
/ Update
和DeleteOnSubmit
方法上使用“this”关键字。
答案 0 :(得分:4)
您不能通过继承以这种方式扩展LINQ-to-SQL实体类型 - 您应该使用partial class
向现有生成的实体添加额外的方法。因为LINQ-to-SQL支持继承(对于有区别的表等),它需要与已知实体类型匹配完全 - 而不是意外的子类。
即
namespace Entities {
partial class User {
/* your extra method(s) here */
}
}
在上面,这是组合与designer.cs中的partial类来创建你的类型。
另一种方法(如果不能选择部分类)是通过扩展方法。
static class EntityExtensions {
public static void SomeMethod(this User user) {...}
}
如果类型之间存在通用方法,则可以通过声明接口,使用 on 接口上的扩展方法,并使用部分类将接口添加到特定类型来执行此操作:
namespace Entities {
partial class User : IFunkyInterface {
/* interface implementation, if necessary */
}
}
static class EntityExtensions {
public static void SomeMethod(this IFunkyInterface obj)
{...}
}
或者如果您需要知道类型:
static class EntityExtensions {
public static void SomeMethod<T>(this T obj)
where T : class, IFunkyInterface
{...}
}
答案 1 :(得分:2)
重新进行枚举编辑(作为第二个答案添加以保持简单)...
首先 - 枚举和值之间是否有直接的1:1映射?例如,如果Basic为7且Administrator为12,则:
enum AccessLevels
{
Basic = 7,
Administrator = 12
}
然后将dbml中该属性的类型(通过设计器)从int更改为(完全限定的)枚举:Entities.AccessLevel
。 LINQ-to-SQL支持枚举作为直接整数映射或直接字符串映射。
如果这不可能(更复杂的场景),您可以隔离存储(int)和面向对象(枚举)模型;将属性重命名为AccessLevelStorage
(或您喜欢的任何其他内容),并在部分类中执行映射:
partial class User {
public AccessLevel AccessLevel {
get {
switch(AccessLevelStorage) {
case 1: return AccessLevelStorage.Foo;
... etc
default: ...throw an exception?
}
}
set {
switch(value) {
case AccessLevel.Foo: AccessLevelStorage = 1; break;
...etc
default: ...throw an exception?
}
}
}
唯一需要注意的是,LINQ查询只能用于存储属性 - 而不是自定义映射属性。如果您在声明上下文的级别执行查询,则可以将存储属性的访问权限更改为internal
- 但如果您在此程序集之外执行查询,则需要将其保留为public。您可能希望添加[Browsable(false)]
以阻止它出现在UI模型中,但这就是它。