Могу ли я создавать вложенные классы при использовании Linq-To-Entities? - PullRequest
3 голосов
/ 30 сентября 2011

Я все еще изучаю Entity Framework и Linq-To-Entities, и мне было интересно, возможно ли утверждение такого рода:

using (var context = new MyEntities())
{
    return (                    
        from a in context.ModelSetA.Include("ModelB")
        join c in context.ModelSetC on a.Id equals c.Id
        join d in context.ModelSetD on a.Id equals d.Id
        select new MyModelA()
        {
            Id = a.Id,
            Name = a.Name,
            ModelB = new MyModelB() { Id = a.ModelB.Id, Name = a.ModelB..Name },
            ModelC = new MyModelC() { Id = c.Id, Name = c.Name },
            ModelD = new MyModelD() { Id = d.Id, Name = d.Name }
        }).FirstOrDefault();
}

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

Невозможно создать постоянное значение типа 'MyNamespace.MyModelB'.В этом контексте поддерживаются только примитивные типы (такие как Int32, String и Guid).

Если я удаляю отображение для ModelB, ModelC и ModelD, оно работает правильно.Я не могу создать новые вложенные классы с Linq-To-Entities?Или я просто пишу это неправильно?

Ответы [ 3 ]

4 голосов
/ 30 сентября 2011

То, что у вас есть, будет хорошо работать с POCO (например, просмотр моделей). Вот пример. Вы просто не можете создавать сущности таким образом.

Кроме того, join является , как правило, неподходящим для запроса L2E. Вместо этого используйте свойства навигации объекта.

2 голосов
/ 02 октября 2011

Я создал вашу модель (насколько я понимаю) с помощью EF 4.1 в консольном приложении:

Если вы хотите проверить ее, добавьте ссылку на EntityFramework.dll и вставьте следующую строку в Program.cs (EF 4.1 создает БД автоматически, если у вас установлен SQL Server Express):

using System.Linq;
using System.Data.Entity;

namespace EFNestedProjection
{
    // Entities
    public class ModelA
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ModelB ModelB { get; set; }
    }

    public class ModelB
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class ModelC
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class ModelD
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    // Context
    public class MyContext : DbContext
    {
        public DbSet<ModelA> ModelSetA { get; set; }
        public DbSet<ModelB> ModelSetB { get; set; }
        public DbSet<ModelC> ModelSetC { get; set; }
        public DbSet<ModelD> ModelSetD { get; set; }
    }

    // ViewModels for projections, not entities
    public class MyModelA
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public MyModelB ModelB { get; set; }
        public MyModelC ModelC { get; set; }
        public MyModelD ModelD { get; set; }
    }

    public class MyModelB
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class MyModelC
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class MyModelD
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Create some entities in DB
            using (var ctx = new MyContext())
            {
                var modelA = new ModelA { Name = "ModelA" };
                var modelB = new ModelB { Name = "ModelB" };
                var modelC = new ModelC { Name = "ModelC" };
                var modelD = new ModelD { Name = "ModelD" };

                modelA.ModelB = modelB;

                ctx.ModelSetA.Add(modelA);
                ctx.ModelSetB.Add(modelB);
                ctx.ModelSetC.Add(modelC);
                ctx.ModelSetD.Add(modelD);

                ctx.SaveChanges();
            }

            // Run query
            using (var ctx = new MyContext())
            {
                var result = (
                    from a in ctx.ModelSetA.Include("ModelB")
                    join c in ctx.ModelSetC on a.Id equals c.Id
                    join d in ctx.ModelSetD on a.Id equals d.Id
                    select new MyModelA()
                    {
                        Id = a.Id,
                        Name = a.Name,
                        ModelB = new MyModelB() {
                            Id = a.ModelB.Id, Name = a.ModelB.Name },
                        ModelC = new MyModelC() {
                            Id = c.Id, Name = c.Name },
                        ModelD = new MyModelD() {
                            Id = d.Id, Name = d.Name }
                    }).FirstOrDefault();
                // No exception here
            }
        }
    }
}

Это работает без проблем.(Я также воссоздал модель из базы данных (которую создал EF 4.1) в EF 4.0: она также работает. Не удивительно, поскольку EF 4.1 ничего не меняет в LINQ для сущностей.)

Теперьвопрос почему вы получаете исключение?Я предполагаю, что есть некоторое важное различие в ваших Моделях или ViewModels или вашем запросе по сравнению с простой моделью выше, которая не видна в вашем примере кода в вопросе.

Но общий результат: проекции во вложенные(не-сущности) классы работают.(Я использую его во многих ситуациях, даже с вложенными коллекциями.) Ответ на ваш вопрос: «Да».

0 голосов
/ 01 октября 2011

То, что опубликовал Крейг, похоже, не работает для вложенных сущностей. Крейг, если я неправильно понял, что вы написали, поправьте меня.

Вот обходной путь, который я нашел, который работает:

using (var context = new MyEntities())
{
    var x = (                    
        from a in context.ModelSetA.Include("ModelB")
        join c in context.ModelSetC on a.Id equals c.Id
        join d in context.ModelSetD on a.Id equals d.Id
        select new { a, b, c }).FirstOrDefault();

    if (x == null)
        return null;

    return new MyModelA()
        {
            Id = x.a.Id,
            Name = x.a.Name,
            ModelB = new MyModelB() { Id = x.a.ModelB.Id, Name = x.a.ModelB..Name },
            ModelC = new MyModelC() { Id = x.c.Id, Name = x.c.Name },
            ModelD = new MyModelD() { Id = x.d.Id, Name = x.d.Name }
        };
}

Поскольку Entity Framework не может обрабатывать создание вложенных классов из запроса, я просто возвратил анонимный объект из моего запроса, содержащий данные, которые я хотел, а затем сопоставил его с моделью

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