Created
October 15, 2013 15:48
-
-
Save Boggin/68c39025069a6f524097 to your computer and use it in GitHub Desktop.
Lookup tables for code-first Entity Framework (with auditing by FrameLog).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Demo.Repository.Models | |
{ | |
public class Country : Lookup | |
{ | |
/// <summary> | |
/// Gets or sets the issues that link to this. | |
/// </summary> | |
/// <remarks>This may be referenced by many issues.</remarks> | |
public ICollection<Issue> Issues { get; set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Demo.Repository | |
{ | |
public class CountryRepository : LookupRepository<Country>, ICountryRepository | |
{ | |
public CountryRepository(IUnitOfWork unitOfWork) : base(unitOfWork) | |
{ | |
} | |
public int UpdateCountries(IEnumerable<Country> countries) | |
{ | |
return this.UpdateLookups(countries); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Demo.Repository.Models | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel.DataAnnotations; | |
public class Issue : ICloneable | |
{ | |
public ICollection<Country> AdditionalCountries { get; set; } | |
public string Country { get; set; } | |
[Key] | |
public int Id { get; set; } | |
[Required] | |
public string Name { get; set; } | |
/// <summary> | |
/// Shallow clone. | |
/// </summary> | |
/// <returns>Returns a <c>MemberwiseClone</c>.</returns> | |
public object Clone() | |
{ | |
return this.MemberwiseClone(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Demo.Repository | |
{ | |
public class IssueRepository : GenericRepository<Issue>, IIssueRepository | |
{ | |
public IssueRepository(IUnitOfWork unitOfWork) : base(unitOfWork) | |
{ | |
} | |
public void SaveIssue(Issue issue, Person user) | |
{ | |
var context = this.UnitOfWork.ApplicationContext; | |
if (issue.Id == 0) | |
{ | |
this.Add(issue); | |
} | |
else | |
{ | |
// fetch the stored entity. | |
var storedIssue = | |
this.DataSet | |
.Include(i => i.AdditionalCountries) | |
.Single(i => i.Id == issue.Id); | |
// update stored entity scalar values. | |
context.Entry(storedIssue).CurrentValues.SetValues(issue); | |
// relationship identifiers provided by update. | |
codes = issue.AdditionalCountries.Select(e => e.Code).ToList(); | |
var countries = UpdateRelationship(codes, storedIssue.AdditionalCountries); | |
foreach (var lookup in countries) | |
{ | |
context.Countries.Attach(lookup); | |
} | |
} | |
// check for user. | |
var person = context.People.FirstOrDefault(p => p.Identifier == user.Identifier); | |
if (person != null) | |
{ | |
user = person; | |
} | |
this.UnitOfWork.Commit(user); | |
} | |
private static List<T> UpdateRelationship<T>( | |
ICollection<string> codes, | |
ICollection<T> lookups) where T : Lookup, new() | |
{ | |
var stored = lookups.Select(x => x.Code).ToList(); | |
// remove relationships that are in the store but not the update. | |
foreach (var code in stored.Where(code => !codes.Contains(code))) | |
{ | |
lookups.Remove(lookups.First(x => x.Code.Equals(code))); | |
} | |
var additions = new List<T>(); | |
// add those relationships that are in the update but not the store. | |
foreach ( | |
var lookup in | |
from code in codes | |
where lookups.All(x => x.Code != code) | |
select new T { Code = code }) | |
{ | |
additions.Add(lookup); | |
lookups.Add(lookup); | |
} | |
return additions; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Demo.Repository.Models | |
{ | |
using System; | |
using System.ComponentModel.DataAnnotations; | |
using FrameLog; | |
public class Lookup : IHasLoggingReference, ICloneable | |
{ | |
[Key] | |
public string Code { get; set; } | |
public string Text { get; set; } | |
// https://bitbucket.org/MartinEden/frame-log/wiki/Home | |
public object Reference | |
{ | |
get | |
{ | |
return this.Code; | |
} | |
} | |
/// <summary> | |
/// Shallow clone. | |
/// </summary> | |
/// <returns>Returns a <c>MemberwiseClone</c>.</returns> | |
public object Clone() | |
{ | |
return this.MemberwiseClone(); | |
} | |
public override bool Equals(object obj) | |
{ | |
if (obj == null || GetType() != obj.GetType()) | |
{ | |
return false; | |
} | |
var y = obj as Lookup; | |
Debug.Assert(y != null, "y != null"); | |
if (y.Text != null) | |
{ | |
return this.Code.Equals(y.Code) && this.Text.Equals(y.Text); | |
} | |
// it's okay to provide this check for adding codes to relationships. | |
return this.Code.Equals(y.Code); | |
} | |
public override int GetHashCode() | |
{ | |
return unchecked((this.Code ?? string.Empty).GetHashCode()); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Demo.Repository | |
{ | |
public class LookupRepository<T> : GenericRepository<T> where T : Lookup | |
{ | |
public LookupRepository(IUnitOfWork unitOfWork) : base(unitOfWork) | |
{ | |
} | |
public IEnumerable<T> GetAllLookups() | |
{ | |
return this.DataSet.ToList(); | |
} | |
public int UpdateLookups(IEnumerable<T> lookups) | |
{ | |
var context = this.UnitOfWork.ApplicationContext; | |
var lookupList = lookups as IList<T> ?? lookups.ToList(); | |
var storedLookups = this.DataSet; | |
var codes = lookupList.Select(c => c.Code).ToList(); | |
foreach (var storedLookup in storedLookups) | |
{ | |
// records that were removed. | |
if (!codes.Contains(storedLookup.Code)) | |
{ | |
storedLookups.Remove(storedLookup); | |
} | |
} | |
foreach (var lookup in lookupList) | |
{ | |
// records that were added. | |
if (storedLookups.All(x => !x.Code.Equals(lookup.Code))) | |
{ | |
storedLookups.Add(lookup); | |
} | |
else | |
{ | |
var storedlookup = storedLookups.First(x => x.Code.Equals(lookup.Code)); | |
// records that were updated. | |
if (!storedlookup.Equals(lookup)) | |
{ | |
context.Entry(storedlookup).CurrentValues.SetValues(lookup); | |
} | |
} | |
} | |
return this.UnitOfWork.Commit(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment