0

我有一个具有以下结构的旧数据库表

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] 不是有效属性。(这是有道理的)

关于我将如何做这件事的任何想法?谢谢!

4

2 回答 2

0

在 Moho 的帮助下,我终于得到了我想要的东西。

此外,您需要确保包含此域实体的项目授予映射项目可见的内部结构。(在 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;
        }
}

这是代码优先映射类

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);
        }
    }
}
于 2013-04-02T21:49:28.997 回答
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) 方法)

于 2013-03-26T21:02:31.950 回答