Возврат указанного типа из метода с EF - PullRequest
1 голос
/ 10 сентября 2011

Как я могу вернуть возвращаемую коллекцию в метод из запроса LINQ, который имеет отношение один ко многим?

Например, у меня есть следующий код, где я могу иметь много проектов для объекта TimeTracking. Будет ли работать тип, который я определил для возвращаемого типа (IEnumerable)? Это настроено в моей модели EF как этот особый тип отношений.

public IEnumerable<TimeTracking> GetTimeTrackings()
        {
            YeagerTechEntities DbContext = new YeagerTechEntities();

            DbContext.Configuration.ProxyCreationEnabled = false;
            DbContext.Configuration.LazyLoadingEnabled = false;

            var timeTrackings = (from timeTrackingProjects in DbContext.TimeTrackings.Include("TimeTrackings.Projects")
                                 select timeTrackingProjects).Where(p => p.TimeTrackingID > 0);

            CloseConnection(DbContext);

            return timeTrackings;
        }

Если это так, когда я отображаю его в моем MVC 3 View, а мой View содержит модель IEnumerable<YeagerTech.YeagerTechWcfService.TimeTracking>, будут ли переменные модели иметь записи для объектов TimeTracking и Project? Я не думаю, что это будет. Мой объект TimeTracking настраивается следующим образом, если только мне не нужно наследовать класс Project с ним (который затем будет иметь свойства Project):

    public partial class TimeTracking
        {
            [DataMember]
            public int TimeTrackingID { get; set; }

            [DataMember]
            public short ProjectID { get; set; }

            [DataMember]
            public byte[] Attachment { get; set; }

            [Required]
            [DataType(DataType.Date)]
            [DataMember]
            public System.DateTime StartDate { get; set; }

            [Required]
            [DataType(DataType.Date)]
            [DataMember]
            public System.DateTime EndDate { get; set; }

            [DataMember]
            public string Notes { get; set; }

            [DataMember]
            public System.DateTime CreatedDate { get; set; }

            [DataMember]
            public Nullable<System.DateTime> UpdatedDate { get; set; }

            [DataMember]    
            public virtual Project Project { get; set; }
        }

Я также хочу, чтобы в моем представлении отображался текст проекта, связанный с TimeTracking, а не значение проекта. Как я могу это сделать? Может кто-нибудь помочь?

Я получил следующее сообщение от вызова метода на моем клиенте WCF.

'невозможно сериализовать, если отслеживание ссылок отключено'

Получив сообщение, я изменил свои DataContracts, добавив ссылки ([DataContract (IsReference = true)]).

namespace YeagerTechModel
{
    [Serializable]
    [DataContract(IsReference = true)]
    public partial class Customer
    {
        public Customer()
        {
            this.Projects = new HashSet<Project>();
        }

        [DataMember]
        public short CustomerID { get; set; }

        [Required]
        [StringLength(50)]
        [DataType(DataType.EmailAddress)]
        [DataMember]
        public string Email { get; set; }

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

Если я посмотрю журнал сообщений WCF, я увижу фактические данные, попадающие в объект Customer, и у него есть объект Project внутри объекта Customer.

Однако после того, как вызов сделан, и я фактически проверяю содержимое переменной customer, я не вижу ссылок на какие-либо данные проекта.

public IEnumerable<Customer> GetCustomers()
        {
            YeagerTechEntities DbContext = new YeagerTechEntities();

            DbContext.Configuration.ProxyCreationEnabled = false;
            DbContext.Configuration.LazyLoadingEnabled = false;

            IQueryable<Customer> customer = DbContext.Customers.Include("Projects").Where(p => p.CustomerID > 0);

            CloseConnection(DbContext);

            return customer;
        }

То, что я хочу сделать сейчас, это ссылаться на данные проекта, возвращаемые после вызова. Тем не менее, я не получаю intellisense объекта Customer после ввода «customer». Это все относится к объекту IQueryable.

Я передаю его обратно в контроллер MVC следующего типа:

IEnumerable<YeagerTechWcfService.Customer> customerList = db.GetCustomers();

и в моем представлении как следующая модель:

IEnumerable<YeagerTech.YeagerTechWcfService.Customer>

Теперь большой вопрос: «Как я могу ссылаться на данные проекта, возвращающиеся в моем представлении?

Ниже приведен мой код для View, но для "item.Project" отсутствует intellisense. Обратите внимание, что «Email» - это свойство внутри моего объекта Customer.

foreach (var item in Model)
        {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Email)
            </td>

Ответы [ 2 ]

1 голос
/ 12 сентября 2011

На самом деле, после дальнейшего просмотра я теперь могу видеть коллекцию Project в своей коллекции Customer вплоть до моего клиента после добавления QucikWatch на объект.

Правильный ответ - последняя частьмой пост, где появляется LazyLoadingEnabled = false.

1 голос
/ 10 сентября 2011

Похоже, что ваш запрос Linq должен быть ближе к этому (ПРИМЕЧАНИЕ: не проверял запрос, возможно, нужно настроить):

var query = (from tt in DbContext.TimeTrackings.Include("Projects")
             where tt.TimeTrackingID > 0
             select tt).ToList();
  • Запрос Linq, как вы написали, является отложенным выполнением, вы закрываете соединение перед извлечением данных, так что это может вызвать ошибку времени выполнения.
  • .Include () должен указывать свойство объекта (TimeTracking в вашем случае), которое необходимо загрузить, поэтому в этом случае это будет свойство Project

После того, как вы получили свою перечисляемую коллекцию сущностей TimeTracking, вы можете получить доступ к свойствам сущности Project, связанной с конкретной сущностью TimeTracking, например:

foreach(var tracking in GetTimeTrackings())
{
    foreach(var project in tracking.Projects)
    {
        // Assuming your Project entity has a Name property
        Response.Write(project.Name);
    }
}

Я не уверен, что вы подразумеваете под

Я также хочу, чтобы в моем представлении отображался текст проекта с TimeTracking, а не со значением Project.

Можете ли вы уточнить, какую собственность от какого объекта вы хотите увидеть? Что такое определение сущности проекта?

В ответ на ваш комментарий о закрытии соединения после получения данных:

  • Оператор IQueryable<Customer> customer = DbContext.Customers.Include("Projects").Where(p => p.CustomerID > 0); фактически не выполняет запрос к базе данных, пока вы не начнете выполнять его итерацию (скорее всего, по вашему мнению, с помощью оператора foreach). Если вы добавите .ToList() в конце этого оператора, он выполнит его и вернет List<Customer> (который также IEnumerable), который содержит все записи, которые являются результатом вашего запроса.
  • Когда вы пытаетесь набрать customer., чтобы получить intellisense для сущности Customer, вы не видите его, потому что customer - это список сущностей Customer (или, скорее, IQueryiable из них), поэтому вам нужно будет сделать что-то вроде customer[0]. для доступа к свойствам первой сущности Customer в этом списке (или итерации по ней).
  • Я не уверен на 100%, как ссылки на сущности проходят в ASP.NET MVC на сущности модели, но действительно простой способ сделать это - создать класс модели, который вы хотите использовать в своем представлении, скажи что-то вроде этого:

    открытый класс TimeTrackingModel {

        public int TimeTrackingID { get; set; }
        public string ProjectName { get; set; }
    

    }

тогда в вашем запросе сделайте это:

var customers = (from tt in DbContext.TimeTrackings.Include("Projects")
                 where tt.TimeTrackingID > 0
                 select new TimeTrackingModel { TimeTrackingID = tt.TimeTrackingID, ProjectName = tt.Project.ProjectName }).ToList();

затем, по вашему мнению, укажите IEnumberable<TimeTrackingModel> в качестве модели, а затем получите доступ к таким свойствам, как это:

foreach (var item in Model)
        {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.ProjectName)
            </td>
...