2014-08-17 1 views
3

Я переношу свой проект с EF 4.0 на EF 6.0. Я пытаюсь получить свойства из навигационной сущности после вставки нового объекта. Этот код работает без каких-либо проблем в EF 4.0, но когда я пытаюсь запустить в EF 6.0, я получаю исключение NullReference.Entity Framework Lazy Загрузка не работает

Entity

Пользователь:

public partial class users 
{ 
    public int RID { get; set; } 
    public string Name { get; set; } 
    public Nullable<int> LangRef { get; set; } 

    public virtual language language { get; set; } 
} 

Язык Entity:

public partial class language 
{ 
    public language() 
    { 
     this.users = new HashSet<users>(); 
    } 

    public int RID { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<users> users { get; set; } 
} 

Код проверки:

test1Entities testEnt = new test1Entities(); 
users user = new users(); 
user.Name = "asd"; 
user.LangRef = 1;//That ID refer to English record in Language entity 
testEnt.users.Add(user); 
testEnt.SaveChanges(); 

string lang = user.language.Name;//Should return "English". However language property seem null 

Модель:

Model:

+0

Где вы теперь находитесь на этом языке? Вы можете установить явный внешний ключ, такой как languageId, или установить языковое свойство для объекта языка, который отслеживается DbContext. – Despertar

+0

Вы посмотрели документацию на [msdn] (http://msdn.microsoft.com/en-us/data/jj713564.aspx)? Мне кажется, что язык и свойства LangRef неправильно отображаются. – kjbartel

+0

@kjbartel Я использую первое приложение базы данных. Я не редактирую в автоматическом сгенерированном коде. Эта модель должна работать нормально. Я не мог найти, где я ошибаюсь. – Dreamcatcher

ответ

0

Вместо использования new users() попробуйте testEnt.users.Create().Разница в том, что возвращенный объект будет прокси-классом, который необходим для ленивой загрузки навигационных свойств.

Как aisde, делают обратные и установку самого language свойства навигации, а не значение внешнего ключа LangRef фактически должен правильно установить свойство LangRef при вызове SaveChanges().

См. DbSet.Create method на MSDN.

+0

Спасибо. Я думаю, что это более эффективное решение для моего дела. – Dreamcatcher

2

Вы говорите, что user.language.Name должен возвращать английский язык, вы нигде не устанавливаете его. Вы должны установить язык при создании нового пользователя.

test1Entities testEnt = new test1Entities(); 
users user = new users(); 
user.Name = "asd"; 
user.LangRef = 1; 

// grab the english language entity from the database 
language englishLanguage = entities.First(o => o.Name == "English"); 

// set the users language to english 
user.language = englishLanuage; 

testEnt.users.Add(user); 
testEnt.SaveChanges(); 

Представьте себе, если вы вставляли пользователя с сырым SQL, вы бы запустить что-то вроде этого

INSERT INTO users (name, languageId) VALUES ('Foo', 1); 

Где 1 является RID из записи в таблице языка, который отображает на английском языке. 1 - это внешний ключ в таблице пользователей, который отображает пользователя на их язык. То же, что и с необработанным SQL, вы должны явно указать Entity Framework, какой язык у пользователя есть. Это делается путем запроса DbContext для языка (который возвращает отслеживаемый объект), а затем установки этого объекта в свойство навигации.


В качестве альтернативы, если вы знаете первичный ключ языка записи заранее, вы можете создать новый объект языка (с правильным RID) и прикрепить его к DbContext, а затем установить его свойство навигации. Это сделало бы так, что есть один меньше запросов к базе данных. Хотя это было бы немного более эффективно, вы должны делать все, что проще/имеет для вас наибольший смысл. Получите его работу, затем вы можете оптимизировать узкие места позже.

language englishLanguage = new language() { RID = 1, Name = "English" }; 
testEnt.languages.Attach(language); 

user.language = englishLanguage; 
testEnt.users.Add(user); 

Edit

Учитывая ваши последние правки, теперь более понятно, что вы пытаетесь сделать. Я не понимал, что LangRef был вашим внешним ключом, поскольку он был десятичным и не соответствует нормальным соглашениям об именах.

Решение описано в этом ответе https://stackoverflow.com/a/18251442/1160036. Проблема возникает из кэширования Entity Framework. После SaveChanges() (чтобы обновить RID), вы можете отсоединить и повторно вытащить пользователя, чтобы обновить его.

testEnt.users.Add(user); 
testEnt.SaveChanges(); 
((IObjectContextAdapter)testEnt).ObjectContext.Detach(user); 
users user = testEnt.First(o => o.RID == user.RID); 
Console.WriteLine(user.language.Name); 

Открытие нового DbContext также работает, но это вызывает другое подключение к базе данных.

Как описано в приведенном выше ответе, testEnt.Entry<users>(user).Reload(), к сожалению, не работает.

+1

Если вы посмотрите модельные изображения, они уже перешли друг к другу. Если я делаю этот запрос everythink, работаем нормально: пользователей newUser = testEnt.users.Include ("language"). FirstOrDefault (x => x.RID == user.RID); Однако это называется Eager loading. Нормальное состояние, когда я пытаюсь получить доступ к свойству Language.Name EF, должен делать новый запрос для языка. Думаю, я пропустил некоторые детали конфигурации. – Dreamcatcher

+0

@Dreamcatcher Я смог реплицировать и решить вашу проблему. Я отредактировал свой ответ. – Despertar

+0

Благодарим вас за решение проблемы с разрешением, **. Include ("language") ** и ** DatabaseObjectContext.Entry (member) .Reload(); ** решение. Однако я упомянул об этом до того, как я перенесю проект Entity Framework 4.0 в Entity Framework 6.0. И есть сотни и сотни строк . Если я начну редактировать код, он будет потреблять много времени. Мне кажется, что Lazy loading помогает подобным ситуациям. Есть ли способ отключить кеширование EF? Спасибо ... – Dreamcatcher