我有一个具有以下结构的遗留数据库表
CREATE TABLE [dbo].[MASTER_PROJECT](
[DATA_ID] [bigint] IDENTITY(1,1) NOT NULL,
......
[GENRE_DATA_ID] [bigint] NULL,
[ADDITIONAL_GENRE_DATA_ID] [bigint] NULL,
[ADDITIONAL_GENRE_2_DATA_ID] [bigint] NULL )
我希望使用EF 5(代码优先)
映射出以下类public class Project {
public long Id {get;set;}
public ICollection<Genre> Genres {get;set;}
}
public class Genre {
public long Id {get;set;}
// other stuff
}
起初我尝试将Genres编成一个数组并像这样映射
HasOptional(t => t.Genres[0]).WithOptionalDependent().Map(m => m.MapKey("GENRE_DATA_ID"));
HasOptional(t => t.Genres[1]).WithOptionalDependent().Map(m => m.MapKey("ADDITIONAL_GENRE_DATA_ID"));
HasOptional(t => t.Genres[2]).WithOptionalDependent().Map(m => m.MapKey("ADDITIONAL_GENRE_2_DATA_ID"));
但这会产生错误,即t.Genres [0]不是有效属性。 (这很有意义)
我对如何做到这一点有任何想法? 谢谢!
答案 0 :(得分:0)
您想要做的事与EF无关 - 您需要使用返回项集合的新方法或属性来实现此实体的部分类。当然,您需要使用各种类型数据ID属性中的值填充此集合。例如:
public ICollection<Genre?> GenreDataIDs
{
get
{
var col = new List<Genre?>() { GENRE_DATA_ID_NavProperty, ADDITIONAL_GENRE_DATA_ID_NavProperty, ..., ADDITION_GENRE_N_DATA_ID_NavProperty };
return col;
}
}
您的导航属性可能名为Genre1,Genre2;为了便于说明,我只是将_NavProperty添加到列名中。
如果要使用集合来更新底层数据库记录,它会变得更复杂(最简单的实现方法是实现SetGenreDataID(int index,int?value)方法)
答案 1 :(得分:0)
在莫霍的帮助下,我终于得到了我想要的东西。
此外,您需要确保包含此域实体的项目授予映射项目可见的内部。 (在AssemblyInfo.cs中)
[assembly: InternalsVisibleTo("YOUR.MAPPING.PROJECT")]
实体定义
public class Project
{
private ObservableCollection<Genre> _genres;
protected internal virtual Genre Genre1 { get; set; }
protected internal virtual Genre Genre2 { get; set; }
protected internal virtual Genre Genre3 { get; set; }
public IList<Genre> Genres
{
get
{
if (_genres == null)
{
_genres = new ObservableCollection<Genre>(new[] {Genre1, Genre2, Genre3});
_genres.CollectionChanged += GenresCollectionChangedHandler;
}
return _genres;
}
}
private void SetGenreByIndex(int index, Genre g)
{
switch (index)
{
case 0: Genre1 = g; break;
case 1: Genre2 = g; break;
case 2: Genre3 = g; break;
}
}
private void GenresCollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e)
{
_genres.CollectionChanged -= GenresCollectionChangedHandler;
int max = 3;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (_genres.Count > max)
{
_genres.RemoveAt(max);
_genres.CollectionChanged += GenresCollectionChangedHandler;
throw new IndexOutOfRangeException("Not allowed to store more than 3 genres.");
}
SetGenreByIndex(_genres.Count - 1, e.NewItems[0] as Genre);
break;
case NotifyCollectionChangedAction.Replace:
for (var i = 0; i < e.NewItems.Count; i++)
SetGenreByIndex(i + e.NewStartingIndex, e.NewItems[i] as Genre);
break;
case NotifyCollectionChangedAction.Reset:
Genre1 = null;
Genre2 = null;
Genre3 = null;
_genres.Clear();
break;
}
_genres.CollectionChanged += GenresCollectionChangedHandler;
}
}
这是Code First Mapping类
public class ProjectConfiguration
{
public ProjectConfiguration()
{
// ...
// GENRES collection
Ignore(t => t.Genres);
HasOptional(t => t.Genre1).WithMany().Map(m => m.MapKey("GENRE_DATA_ID"));
HasOptional(t => t.Genre2).WithMany().Map(m => m.MapKey("GENRE_DATA_ID_1"));
HasOptional(t => t.Genre3).WithMany().Map(m => m.MapKey("GENRE_DATA_ID_2"));
}
}
这是一种确保其有效的测试方法
[TestClass]
public class ProjectUnitTests
{
[TestMethod]
public void SwapGenresInListAndSaveTest()
{
//Arrange
Genre original1 = null;
Genre original2 = null;
using (var context = new MyContext())
{
context.Configuration.LazyLoadingEnabled = true;
//ACT
var project = context.Projects.Find(2341);
original1 = project.Genres[0];
original2 = project.Genres[1];
genres[0] = original2;
genres[1] = original1;
//Save to DB
context.SaveChanges();
}
//ASSERT
using (var context = new MyContext())
{
var project1 = context.Projects.Find(2341);
//ASSERT
Assert.IsNotNull(project1);
Assert.IsNotNull(project1.Genres);
Assert.AreEqual(3, project1.Genres.Count);
Assert.AreEqual(original2.DataId, project1.Genres[0].DataId);
Assert.AreEqual(original1.DataId, project1.Genres[1].DataId);
}
}
}