Расширение сущностей DataContext - использование InsertOnSubmit (this) внутри дочернего класса - PullRequest
2 голосов
/ 04 мая 2009

Я расширяю эту сущность 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?


Обновление:


Расширение класса сущностей: переопределение свойства с помощью перечислителя, в то же время возможность использовать ключевое слово "this" в методах Insert / Update и DeleteOnSubmit в экземпляре DataContext

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? - это без изменения сигнатуры класса сущностей, поэтому я могу использовать "this "ключевое слово для Insert / Update и DeleteOnSubmit методов в DataContexts.

Ответы [ 2 ]

4 голосов
/ 04 мая 2009

Вы не можете таким образом расширять типы сущностей LINQ-to-SQL через наследование - вместо этого вы должны использовать partial class для добавления дополнительных методов к существующей сгенерированной сущности. Поскольку LINQ-to-SQL поддерживает наследование (для разграниченных таблиц и т. Д.), Ожидается, что точное совпадение с известным типом сущности - не неожиданные подклассы.

т.е.

namespace Entities {
    partial class User {
        /* your extra method(s) here */
    }
}

В приведенном выше примере это в сочетании с частичным классом в designer.cs для создания вашего типа.

Другой способ сделать это (если частичный класс не является опцией) - через метод расширения.

static class EntityExtensions {
    public static void SomeMethod(this User user) {...}
}

Если существуют методы, общие для типов, вы можете сделать это, объявив интерфейс, используя методы расширения для этого интерфейса и используя частичные классы для добавления интерфейса к определенным типам:

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
    {...}
}
2 голосов
/ 04 мая 2009

Re enum edit (добавлено в качестве второго ответа для простоты) ...

Во-первых, существует ли прямое отображение 1: 1 между перечислением и значениями? Например, если Basic равен 7, а Administrator равен 12, то:

enum AccessLevels
{
    Basic = 7,
    Administrator = 12
}

Затем измените тип этого свойства в dbml (через конструктор) с int на ваше (полностью квалифицированное) перечисление: Entities.AccessLevel. LINQ-to-SQL поддерживает перечисления как прямые целочисленные, так и прямые строковые сопоставления.

Если это невозможно (более сложные сценарии), вы можете изолировать модели хранения (int) и объектно-ориентированные (enum); переименуйте свойство в 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 будут работать только со свойствами storage , а не со свойством сопоставленного пользователя. Если вы выполняете свои запросы на уровне, который объявляет контекст, вы можете изменить доступ к свойству хранилища на internal - но если вы делаете запросы вне этой сборки, вам нужно будет оставить это открытым Возможно, вы захотите добавить [Browsable(false)], чтобы он не появлялся в моделях пользовательского интерфейса, но это все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...