Question

Background: I am parsing an XML file (book signing events information), and then attempting to create database records based on the Parsed data via Entity Framework Code First (with the help of Entity Framework Power Tools Beta 3).

After sorting the parsing logic, I have the following code for storing the parsed data to the database:

using (var context = new BSContext())
{
    foreach (var e in events)
    {
        try
        {                    
            // Create the Author Entity
            var AuthorEntity = parser.getAuthorByName(e.Author);
            if (AuthorEntity == null)
            {
                AuthorEntity = new Author()
                {
                    Name = e.Author
                };
                context.Authors.Add(AuthorEntity);
                context.SaveChanges();
            }                        


            // Create the Location Entity
            var LocationEntity = parser.getLocationByNameAddressAndPostCode(e.Location.Name, e.Location.Address, e.Location.PostCode);
            if (LocationEntity == null)
            {
                LocationEntity = new Location()
                {
                    Name = e.Location.Name,
                    Address = e.Location.Address,
                    City = e.Location.City,
                    County = e.Location.County,
                    PostCode = e.Location.PostCode,
                    Telephone = e.Location.Telephone
                };
                context.Locations.Add(LocationEntity);
                context.SaveChanges();
            }                        


            // Create the Book Entity
            var BookEntity = parser.getBookByName(e.Book.Name);
            if(BookEntity == null)
            {
                BookEntity = new Book()
                {
                    Name = e.Book.Name,
                    BookImgUrl = e.Book.BookImgUrl
                };
                context.Books.Add(BookEntity);
                context.SaveChanges();
            }


            // Create the Event Entity
            string dtObjFormat = "dd MMM yyyy HH:mm";
            DateTime dt;
            var EventEntity = new Event()
            {
                Author = AuthorEntity,
                Book = BookEntity,
                Info = e.Info,
                Start = DateTime.TryParseExact(e.Date + " " + e.Time, dtObjFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt) ? dt : new DateTime(),
                Location = LocationEntity
            };
            context.Events.Add(EventEntity);
            context.SaveChanges();
        }
        catch
        {
            Console.WriteLine("Something went wrong!");
        }
    }
    Console.WriteLine("Looped through all Events");
}

The Code above, attempts to create entities and save them to the database. And when the need arises, re-use the saved entities.

So for example, in my XML file, an author appears twice, but I don't want to create two records for that author, since I have already created a record on a previous loop for that same author. Even though to my mind I have code that takes care of that (see above), it still for some reason creates multiple Author records. Same issue with Books too.

The getAuthorByName(String authorName) method has the following code:

/// <summary>
/// A method to get an Author Entity by name. If no Author exists, then
/// NULL is returned. If two authors exist with the exact same name,
/// then the first encountered is returned.
/// </summary>
/// <param name="authorName">The name of the Author.</param>
/// <returns>The Author Entity</returns>
public Author getAuthorByName(String authorName)
{
    using (var context = new BSContext())
    {
        return context.Authors.FirstOrDefault(x => x.Name == authorName);
    }
}

The two other methods getBookByName(String bookName) and getLocationByNameAddressAndPostCode(String lName, String lAddress, String lPostCode) both have similar logic as the method above.

Problem: Stop duplication of records in the database for the entities Book and Author.

Was it helpful?

Solution

What you should note here is that you have 2 active BSContext objects being used. Entity tracking happens with each of these Context separately. Aka Author will live in one, not both unless you query for it within both.

Once you have finished the getAuthorByName method the Author entity will have been detached from any Entity Context. What you would have to do is re-attach this entity to the outer context ( aka the one in the top most code example). If you don't, as in the code above, the BSContext isn't aware that it is an existing entity and believes it to be a new one. Resulting in a new Author being inserted into the database.

Or you could try do this instead.

/// <summary>
/// A method to get an Author Entity by name. If no Author exists, then
/// NULL is returned. If two authors exist with the exact same name,
/// then the first encountered is returned.
/// </summary>
/// <param name="authorName">The name of the Author.</param>
/// <returns>The Author Entity</returns>
public Author getAuthorByName(BSContext context, String authorName)
{
        return context.Authors.FirstOrDefault(x => x.Name == authorName);
}

And then call parser like

var AuthorEntity = parser.getAuthorByName(context, e.Author);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top