Linq to Entities - 3-уровневая архитектура - PullRequest
6 голосов
/ 11 июля 2011

За последние несколько месяцев я много узнал о Linq-To-Entities и 3-уровневой архитектуре с DAO / DAL / Repository.Теперь у меня в голове есть несколько вещей, которые продолжают беспокоить меня.У меня есть три вопроса, которые вы увидите ниже.

Существует множество способов заставить хранилище работать, но каким образом можно «заставить» работать хранилище с точки зрения производительности.

1) Инициализировать текст данных в конструкторе

public class Repository : IRepository
{

    private Datacontext context;

    public Repository()
    {
        context = new Datacontext();
    }

    public IList<Entity> GetEntities()
    {
        return (from e in context.Entity
                select e).ToList();
    }
}

2) Использовать «Использование»

public class Repository : IRepository
{
    public IList<Entity> GetEntities()
    {
        using (Datacontext context = new Datacontext())
        {
            return (from e in context.Entity
                    select e).ToList();
        }

    }
}

3) По-другому (пожалуйста, прокомментируйте)

Я оставлю здесь ваше предложение, чтобы другие могли прокомментировать


Также, кажется, некоторые люди говорятрепозиторий должен возвращать IQueryable для бизнес-уровня, в то время как другие говорят, что лучше возвращать IList.Каково ваше мнение по этому поводу?


Приведенные выше примеры кода в первом вопросе указывают на хранилище, но как лучше всего реализовать хранилище на бизнес-уровне (инициализируйте в конструкторе, используйте "Используя "??)

Ответы [ 5 ]

2 голосов
/ 11 июля 2011

Либо работает, я думаю.Главное, что вы должны сделать контексты вашего объекта достаточно недолговечными (ИМХО).Поэтому я думаю, что у вас есть два варианта: -

  1. Создать / уничтожить контекст в рамках одного вызова метода, например, оператора using согласно вашему второму примеру.

  2. Создание / уничтожение контекста при создании / уничтожении репозитория - в этом случае ваш репозиторий должен реализовывать IDisposable и сам должен быть заключен в оператор using и должен быть недолговечным.Преимущество этого подхода заключается в том, что ваши методы хранилища просто выполняют запрос, поэтому использование метода (new ObjectContext ()) не загрязняет метод;оборотная сторона заключается в том, что репозитарий передается клиенту для утилизации репозитория.Использование этого механизма означает, что вы также можете создавать запросы в IQueryable <> (при условии, что вы выполняете запрос перед удалением хранилища).Например:

репозиторий открытого класса: IDisposable {DataHubContext context = new DataHubContext ();

public IQueryable<Payment> GetPayments()
{
    return context.Payments;
}

public void Dispose()
{
    context.Dispose();
}

}

Форматирование прошло немногосмешно в ТАК - извините .... А потом в ваш телефонный код: -

public class ClientCode
{
    public void DisplayPaymentsOnScreen()
    {
        Payment[] payments;

        using (var repository = new Repository())
        {
            payments = repository.GetPayments().Where(p => p.Amount > 100).ToArray();
        }

        // Do stuff with the data here...
    }
}
1 голос
/ 11 июля 2011

Я думаю, что это зависит от ваших потребностей ...

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

Пример репозитория будет выглядеть примерно так: *

public class Repository : IRepository
{

private Datacontext context;

public Repository()
{
    context = new Datacontext();
}

public IList<Entity> GetEntities()
{
    return (from e in context.Entity
            select e).ToList();
}

public void Save()
{
    context.SubmitChanges();
}
}

... тогда вы можете сделать много данныхизменения и отправить в базу данных за один раз.Еще один момент, о котором стоит подумать, это то, что в ваших GetEntities у вас есть вызов ToList ().Когда вы вызываете это, вы фактически выполняете запрос к базе данных тут же.Если вы планируете выполнять дальнейшую логическую обработку результатов, вы можете вместо этого вернуть IQueryable и вызывать ToList только тогда, когда вам действительно нужно использовать список

0 голосов
/ 11 июля 2011

Для себя я бы всегда возвращал IQueryable<T>

public IQueryable<Entity> GetEntities()
{
    return from e in context.Entity select e;
}

Вы должны прочитать об отложенном выполнении http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx Я использую его, чтобы в бизнес-логике или в пользовательском интерфейсе я запрашивал точные части объекта, а не весь объект (например, select *)

Я предпочитаю инициализировать контекст в конструкторе

public class Repository : IRepository
{

 private Datacontext context;

 public Repository()
 {
     context = new Datacontext();
 }

 public IQueryable<Entity> GetEntities()
 {
     return from e in context.Entity select e;
 }  

 public int Save()
 {
     // Return the number of the affected rows to determine in your code whether your query executed or not 
     return context.SubmitChanges();
 }


}

Примечание: Также при проектировании хранилища EF убедитесь, что у вас есть один экземпляр контекста во всех хранилищах, чтобы избежать ошибок во время обновления и удаления.

У меня есть общий репозиторий, который я создал в своей компании, и я планирую в ближайшее время опубликовать его в блоге, он позволит вам легко выполнять операции CRUD и расширять его по своему усмотрению, используя всего несколько строк кода. После того, как я закончу это, я обновлю ответ с URL

0 голосов
/ 11 июля 2011

Если вы хотите, чтобы ваши методы не позволяли составить наиболее точный запрос, используйте первый случай.Например:

public class Repository : IRepository
{

    private Datacontext context;

    public Repository()
    {
        context = new Datacontext();
    }

    public IQueryabale<Entity> SelectAllEntities()
    {
         return context.Entity.Where(e=>! e.IsObsolote);
    }

    public IQueryable<Entity> SelectAllEntityRelatedToAnotherEntity(Entity otherEntity)
    {
         return this.SelectAllEntities().Where(e=>e.RelatedEntityId == otherEntity.Id);
    }
}

РЕДАКТИРОВАТЬ

You can use it in collaboration with your business layer like this:

public class EntityManager()
{
     public IQueryable<Entities> FindAllApprovedEntities(Entity other)
     {
          return new Repository().SelectAllEntityRelatedToAnotherEntity(other).Where(e=>e.Approved);
     }
}
0 голосов
/ 11 июля 2011

Я бы предпочел использование шаблона, поскольку это позволяет коду быть более чистым и простым, так как мы знаем область действия контекста БД и можем четко сказать, когда это удаляется, что трудно сказать в случае конструктора.

Кроме того, я не думаю, что вы можете вернуть IQueryable в случае «использования», так как контекст db будет удален, как только завершится использование блока, и тогда вы не сможете использовать возвращенный IQueryable на бизнес-уровне.

...