Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Domain Modeling Question using C# with Entity Framework CTP 4

I am trying to model out a album that has a collection of photos. Each Album will have a collection of Photos and a Photo that is a thumb. This is what I have but EF does not seem to like it:

public class Album : IEntity {
        private DateTime _dateCreated;

        public Album() {
            _dateCreated = SystemTime.Now();
            Photos = new List<Photo>();
        }
        public long Id { get; set; }
        public string Name { get; set; }
        public string Location { get; set; }
        public DateTime DateCreated
        {
            get { return _dateCreated; }
            set { _dateCreated = value; }
        }
        public virtual Site Site { get; set; }
        public virtual Photo Thumbnail { get; set; }
        public virtual ICollection<Photo> Photos { get; set; }
    }

public class Photo : IEntity {
            public Photo() {
                _dateCreated = SystemTime.Now();
            }
            private DateTime _dateCreated;
            public long Id { get; set; }
            public string Caption { get; set; }
            public string FileName { get; set; }
            public DateTime DateCreated
            {
                get { return _dateCreated; }
                set { _dateCreated = value; }
            }
            public virtual Album Album { get; set; }

        }

 public class AlbumMap : EntityConfiguration<Album>
    {
        public AlbumMap()
        {
            HasKey(x => x.Id);
            Property(x => x.Id).IsIdentity();
            Property(x => x.Location).IsVariableLength().HasMaxLength(80);
            Property(x => x.Name).IsVariableLength().HasMaxLength(80).IsRequired();
            Property(x => x.DateCreated);
            MapSingleType(a => new
            {
                a.Id,
                SiteId = a.Site.Id,
                ThumbnailId = a.Thumbnail.Id,
                a.Location,
                a.Name,
                a.DateCreated
            }).ToTable("Albums");
        }
    }

public class PhotoMap : EntityConfiguration<Photo>
    {
        public PhotoMap()
        {
            HasKey(x => x.Id);
            Property(x => x.Id).IsIdentity();
            Property(x => x.FileName).IsVariableLength().HasMaxLength(255).IsRequired();
            Property(x => x.Caption).IsVariableLength().HasMaxLength(255);
            Property(x => x.DateCreated);
            MapSingleType(a => new
            {
                a.Id,
                SiteAlbumId = a.Album.Id,
                a.FileName,
                a.Caption,
                a.DateCreated
            }).ToTable("AlbumPhotos");
        }
    }

Am I missing something or does this look right? I am expecting EF to generate a 1 to many in my database but it keeps creating a reference table between Album and Photos (Album_Photos) but this should not be a many-to-many. Any help would be great.

like image 942
Paul Avatar asked Dec 04 '10 21:12

Paul


People also ask

What is domain model and examples?

The Domain Model is an object model of the domain that incorporates both behavior and data. In the example of the e-commerce app, we need to deal with the domain logic of customers who want to buy products and return them if they want.

What is a domain model computer science?

The domain model is a representation of meaningful real-world concepts pertinent to the domain that need to be modeled in software. The concepts include the data involved in the business and rules the business uses in relation to that data. A domain model leverages natural language of the domain.


1 Answers

By convention, EF code first does not create a link table in typical one to many scenario, the reason that you are getting it is because your associations between Album and Photo objects has been taken by EF as being a kind of many to many association:
Each album has a collection of Photos and also each Photo has a collection of Albums that this photo is a thumbnail for (although the related navigation property is not explicitly specified on Photo class and only Album has a Thumbnail property).

Solution:

As of EF CTP4, the only way to fix this is by leveraging Fluent API, but before that, I modify your model a little bit and add two explicit FKs to your model to give you ultimate flexibility to work with your objects. They are AlbumId on Photo and ThumbnailId on Album:

public class Photo {        
    public long Id { get; set; }
    public string Caption { get; set; }
    public string FileName { get; set; }
    public DateTime DateCreated { get; set; }

    public long AlbumId { get; set; }
    public virtual Album Album { get; set; }
}

public class Album {
    public long Id { get; set; }
    public string Name { get; set; }
    public string Location { get; set; }
    public DateTime DateCreated { get; set; }

    public long ThumbnailId { get; set; }
    public virtual Photo Thumbnail { get; set; }

    public virtual ICollection<Photo> Photos { get; set; }
}

public class PhotoMap : EntityConfiguration<Photo> {
    public PhotoMap() 
    {
        this.HasRequired(p => p.Album)
            .WithMany(a => a.Photos)
            .HasConstraint((p, a) => p.AlbumId == a.Id);

        Property(x => x.FileName).IsVariableLength().HasMaxLength(255)
                                                    .IsRequired();
        Property(x => x.Caption).IsVariableLength().HasMaxLength(255);
        MapSingleType(p => new {
            p.Id,
            SiteAlbumId = p.AlbumId,
            p.FileName,
            p.Caption,
            p.DateCreated
        })
        .ToTable("Photo");
    }
}

public class AlbumMap : EntityConfiguration<Album> {
    public AlbumMap()
    {
        this.HasRequired(a => a.Thumbnail)
            .WithMany()
            .WillCascadeOnDelete(false)
            .HasConstraint((a, p) => p.Id == a.ThumbnailId);

        Property(x => x.Location).IsVariableLength().HasMaxLength(80);
        Property(x => x.Name).IsVariableLength().HasMaxLength(80).IsRequired();
        MapSingleType(a => new {
            a.Id,
            a.ThumbnailId,
            a.Location,
            a.Name,
            a.DateCreated
        })
        .ToTable("Album");
    }
}


This results to the following desired schema: alt text

like image 125
Morteza Manavi Avatar answered Oct 13 '22 17:10

Morteza Manavi