I have four classes defined as follows:
public class Operator : Base
{
public string Name { get; set; }
public string URL { get; set; }
public ICollection<Address> Addresses { get; set; }
public ICollection<Contact> Contacts { get; set; }
public ICollection<Application.Application> Applications { get; set; }
}
public class Address : Base
{
public String Street{ get; set; }
public int? ParentId { get; set; }
public Operator Parent { get; set; }
public ICollection<Application.Application> Applications { get; set; }
}
public class Contact : Base
{
public string Name { get; set; }
public int? ParentId { get; set; }
public Operator Parent { get; set; }
public ICollection<Application.Application> Applications { get; set; }
}
public class Application : Base
{
[MaxLength(300)]
public String Name { get; set; }
public ICollection<Operator.Operator> Operators { get; set; }
public ICollection<Operator.Address> Addresses { get; set; }
public ICollection<Operator.Contact> Contacts { get; set; }
}
public class Base
{
public int Id { get; set; }
//public int BaseObjectId { get; set; }
TimeZoneInfo _easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
private DateTime _modifiedDate;
public DateTime ModifiedDate
{
get { return this._modifiedDate; }
set
{
this._modifiedDate = DateTime.SpecifyKind(value, DateTimeKind.Unspecified);
this._modifiedDate = TimeZoneInfo.ConvertTimeFromUtc(this._modifiedDate, _easternZone);
}
}
private DateTime _createdDate;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedDate
{
get { return this._createdDate; }
set
{
this._createdDate = DateTime.SpecifyKind(value, DateTimeKind.Unspecified);
this._createdDate = TimeZoneInfo.ConvertTimeFromUtc(this._createdDate, _easternZone);
}
}
public bool Disabled { get; set; }
}
public class DB : DbContext
{
public DbSet<EF.Complaint.Complaint> Complaints { get; set; }
public DbSet<EF.Category.Category> Categories { get; set; }
public DbSet<EF.Action.Action> Actions { get; set; }
public DbSet<EF.Medium.Medium> Mediums { get; set; }
public DbSet<EF.Priority.Priority> Priorities { get; set; }
public DbSet<EF.Complaint.Comment> Comments { get; set; }
public DB()
{
this.Database.Log = s => { System.Diagnostics.Debug.WriteLine(s); };
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
modelBuilder.Configurations.Add(new ComplaintConfig());
modelBuilder.Configurations.Add(new CategoryConfig());
modelBuilder.Configurations.Add(new ActionConfig());
modelBuilder.Configurations.Add(new MediumConfig());
modelBuilder.Configurations.Add(new PriorityConfig());
modelBuilder.Configurations.Add(new CommentConfig());
base.OnModelCreating(modelBuilder);
}
}
Operator, Contact and Address can all belong to a particular application. So you could have a structure like this:
Operator 1 - belongs to App1 and App2
Child contact 1 - belongs to App1
Child Contact 2 - belongs to App2
Child Address 1 - belongs to App2
I am trying to build a method that returns a list of Operators for a particular Application and includes Addresses and Contacts of that operator that also belong to that Application
Here is a query I have concocted so far
public IEnumerable<Operator> GetForApp(string name)
{
return (Context.Operators.Where(x => x.Applications.Any(y => y.Name == name))
.Select(x => new
{
x,
Addresses = x.Addresses.Where(y => y.Applications.Any(z => z.Name == name)),
Contacts = x.Contacts.Where(y => y.Applications.Any(z => z.Name == name)),
Applications = x.Applications
}).AsEnumerable()
.Select(n => n.x));
}
This works in a sense that the basic members of Operator get loaded as well as Addresses and Contacts get loaded and filtered correctly...What doesn't get loaded is Applications and I can't figure out why. They only difference I see is that Addresses/Contacts and Operator is many-to-one and Applications and Operator is many-to-many.
You must use lazy loading feature or include your related object directly in your query.
public class Operator : Base
{
public string Name { get; set; }
public string URL { get; set; }
public ICollection<Address> Addresses { get; set; }
public ICollection<Contact> Contacts { get; set; }
// by adding virtual keyword EF could generate proxy classes and
// fetch actual objects when are needed.
public virtual ICollection<Application.Application> Applications { get; set; }
}
Or in your query directly include Application:
public IEnumerable<Operator> GetForApp(string name)
{
return (Context.Operators.Where(x => x.Applications.Any(y => y.Name == name))
.Include(x=>x.Applications)
.Select(x => new
{
x,
Addresses = x.Addresses.Where(y => y.Applications.Any(z => z.Name == name)),
Contacts = x.Contacts.Where(y => y.Applications.Any(z => z.Name == name)),
Applications = x.Applications
}).AsEnumerable()
.Select(n => n.x));
}
Related
I have 6 classes where the first class Money, goes deep 5 levels with objects. Whatever I try I cannot get this representation, so I hope someone would be kind to offer some help. At least for first 2,3 levels then I can continue.
public class Money
{
public Money()
{
Dollars = new HashSet<MoneyDetails>();
Pesos = new HashSet<MoneyDetails>();
Pounds = new HashSet<MoneyDetails>();
}
public int Id { get; set; }
public virtual ICollection<MoneyDetails> Dollars { get; }
public virtual ICollection<MoneyDetails> Pesos { get; }
public virtual ICollection<MoneyDetails> Pounds { get; }
public string Note { get; }
}
public class MoneyDetails
{
public MoneyDetails()
{
Valuations = new HashSet<Valuations>();
}
public int Id { get; set; }
public string Description { get; set; }
public double Value { get; set; }
public virtual ICollection<Valuation> Valuations { get; set; }
}
public class Valuations
{
public Valuations ()
{
Lows = new HashSet<Deep>();
Highs = new HashSet<Deep>();
}
public int Id { get; set; }
public string Sum { get; set; }
public virtual ICollection<Deep> Lows { get; set; }
public virtual ICollection<Deep> Highs { get; set; }
}
public class Deep
{
public Deep()
{
Shallows = new HashSet<Shallow>();
}
public int Id { get; set; }
public object Data { get; set; }
public virtual ICollection<Shallow> Shallows { get; set; }
}
EDIT :
I'm using Entity Framework Core.
Following is the configuration I tried myself.
You can see below how I started, I just don't know how to go deeper into objects and make relationships between them so they are connected.
public void Configure(EntityTypeBuilder<Money> builder)
{
builder.ToTable("Money");
builder.HasKey(e => e.Id);
builder.HasMany(s => s.Dollars)
.WithOne(ad => ad.Money)
.HasForeignKey(i => i.MoneyId);
builder.HasMany(s => s.Pesos)
.WithOne(ad => ad.Money)
.HasForeignKey(i => i.MoneyId);
builder.HasMany(s => s.Pounds)
.WithOne(ad => ad.Money)
.HasForeignKey(i => i.MoneyId);
}
You are using -
.WithOne(ad => ad.Money)
.HasForeignKey(i => i.MoneyId);
in your configuration code, but you don't have a Money navigation property or a MoneyId foreign-key property in MoneyDetails.
Since you are not using navigation and foreign-key properties in any of your entity models, I'd suggest not to configure the relations manually. Configure other properties in the Configure method if you need, but do not configure the relations. That way, EF will automatically create nullable foreign-keys in your tables and use them as Shadow Property.
EDIT - A better solution for you :
Even though the suggestion above will create all your tables with all the relations, I'm confused about how you plan to use those relations. For example, in the Money entity model Dollars, Pesos, Pounds are all collections of MoneyDetails. Therefore, all the following queries -
var money = myDbContext.Money.Include(p=> p.Dollars).FirstOrDefault(p=> p.Id == someId);
var money = myDbContext.Money.Include(p=> p.Pesos).FirstOrDefault(p=> p.Id == someId);
var money = myDbContext.Money.Include(p=> p.Pounds).FirstOrDefault(p=> p.Id == someId);
will give you the same result - the Money with the specified Id, with a list of all related MoneyDetails. So, there's no point of having three collection properties and three different relations.
Try the following approach to filter related data (you need EF Core 5.0) -
Create enum to identify the entity type -
public enum MoneyDetailsType { Dollar = 1, Peso = 2, Pound = 3 }
public enum DeepType { High = 1, Low = 2 }
Modify your entity models like -
public class Money
{
public Money()
{
MoneyDetails = new HashSet<MoneyDetails>();
}
public int Id { get; set; }
public string Note { get; }
public virtual ICollection<MoneyDetails> MoneyDetails { get; set; }
}
public class MoneyDetails
{
public MoneyDetails()
{
Valuations = new HashSet<Valuations>();
}
public int Id { get; set; }
public string Description { get; set; }
public double Value { get; set; }
public MoneyDetailsType Type { get; set; } // added - type
public int MoneyId { get; set; } // added - foreign-key
public Money Money { get; set; } // added - navigation property (optional)
public virtual ICollection<Valuations> Valuations { get; set; }
}
public class Valuations
{
public Valuations ()
{
Deeps = new HashSet<Deep>();
}
public int Id { get; set; }
public string Sum { get; set; }
public int MoneyDetailsId { get; set; } // added - foreign-key
public MoneyDetails MoneyDetails { get; set; } // added - navigation property (optional)
public virtual ICollection<Deep> Deeps { get; set; }
}
public class Deep
{
public int Id { get; set; }
public string Data { get; set; }
public DeepType Type { get; set; } // added - type
public int ValuationsId { get; set; } // added - foreign-key
public Valuations Valuations { get; set; } // added - navigation property (optional)
}
Notice, in Deep entity, currently you have Data as of type object which is not allowed. You have to change it to some primitive type. I'm using it as string. I have also omitted the Shallows property since you haven't added the Shallow model.
Your configuration methods should look like -
public void Configure(EntityTypeBuilder<Money> builder)
{
builder.ToTable("Money");
builder.HasMany(p => p.MoneyDetails)
.WithOne(p => p.Money)
.HasForeignKey(p => p.MoneyId);
}
public void Configure(EntityTypeBuilder<MoneyDetails> builder)
{
builder.ToTable("MoneyDetails");
builder.Property(p => p.Type).IsRequired(true).HasConversion(new EnumToStringConverter<MoneyDetailsType>());
builder.HasMany(p => p.Valuations)
.WithOne(p => p.MoneyDetails)
.HasForeignKey(p => p.MoneyDetailsId);
}
public void Configure(EntityTypeBuilder<Valuations> builder)
{
builder.ToTable("Valuations");
builder.HasMany(p => p.Deeps)
.WithOne(p => p.Valuations)
.HasForeignKey(p => p.ValuationsId);
}
public void Configure(EntityTypeBuilder<Deep> builder)
{
builder.ToTable("Deep");
builder.Property(p => p.Type).IsRequired(true).HasConversion(new EnumToStringConverter<DeepType>());
}
If you don't want to include the navigation properties in your entity models, then you can just keep the .WithOne() method empty in your configuration, like -
builder.HasMany(p => p.MoneyDetails)
.WithOne()
.HasForeignKey(p => p.MoneyId);
Now you can query like -
var money = myDbContext.Money
.Include(p=> p.MoneyDetails.Where(r=> r.Type == MoneyDetailsType.Dollar))
.FirstOrDefault(p=> p.Id == someId);
and it will give you the Money with a list of only Dollar type MoneyDetails.
I have migrated from Entity Framework 6 to EF Core and also Web Api .net framework to .net core.
I have many to many relationship that I have set up as follows
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var instrumentsToPlaces = modelBuilder.Entity<InstrumentPlace>();
instrumentsToPlaces.ToTable("InstrumentsToPlaces");
instrumentsToPlaces.HasKey(x => new { x.PlaceId, x.InstrumentId });
instrumentsToPlaces.HasOne(i => i.Instrument)
.WithMany(p => p.InstrumentsPlaces)
.HasForeignKey(ip => ip.InstrumentId);
instrumentsToPlaces.HasOne(p => p.Place)
.WithMany(i => i.InstrumentsPlaces)
.HasForeignKey(ip => ip.PlaceId);
var instrumentsToStyle = modelBuilder.Entity<InstrumentStyle>();
instrumentsToStyle.ToTable("InstrumentsToStyles");
instrumentsToStyle.HasKey(x => new { x.StyleId, x.InstrumentId });
instrumentsToStyle.HasOne(i => i.Instrument)
.WithMany(s => s.InstrumentStyles)
.HasForeignKey(si => si.InstrumentId);
instrumentsToStyle.HasOne(s => s.Style)
.WithMany(i => i.InstrumentStyles)
.HasForeignKey(si => si.StyleId);
}
I have included the navigation properties in the repository method as follows
public Instrument GetInstrumentByName(string name)
{
using (var starsAndCatzDbContext = new StarsAndCatzDbContext())
{
var instrument = _starsAndCatzDbContext.Instruments
.Include(a=>a.InstrumentsPlaces)
.ThenInclude(a=>a.Place)
.Include(a=>a.InstrumentStyles)
.ThenInclude(a=>a.Style)
.FirstOrDefault(i => i.Name == name);
return instrument;
}
}
Here are the classes
public class Instrument {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<InstrumentPlace> InstrumentsPlaces { get; set; }
public virtual ICollection<InstrumentStyle> InstrumentStyles { get; set; }
}
public class InstrumentPlace
{
public int InstrumentId { get; set; }
public Instrument Instrument { get; set; }
public int PlaceId { get; set; }
public Place Place { get; set; }
}
public class InstrumentStyle
{
public int InstrumentId { get; set; }
public Instrument Instrument { get; set; }
public int StyleId { get; set; }
public Style Style { get; set; }
}
public class Style {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<InstrumentStyle> InstrumentStyles { get; set; }
}
public class Place {
public int Id { get; set; }
public string Name { get; set; }
public string Division { get; set; }
public int Tier { get; set; }
public string State { get; set; }
public string Postcode { get; set; }
public float? Latitude { get; set; }
public float? Longitude { get; set; }
public virtual ICollection<InstrumentPlace> InstrumentsPlaces { get; set; }
}
The WebAPI method to be called is
[HttpGet("GetInstrumentByName/{suburb}/{instrument}"), Produces("application/json")]
public Instrument GetInstrumentByName(string suburb, string instrument)
{
try
{
var result = _instrumentRepository.GetInstrumentByName(instrument);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new Instrument();
}
}
When I send the request to "/api/instruments/west-end/guitar" I get the expected result when I place a breakpoint before sending the response as follows
As you notice, the Navigation properties are loaded (when I expand the collections I can see all the properties being loaded as well).
However the json response I receive is the following
Any suggestions or am I missing something here?
Thank you all in advanced
Thanks #H. Herzl for giving me a hint.
The solution was found in this other question
services.AddMvc().AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
https://stackoverflow.com/a/40501464/1513346
Scenario
public class Product : Entity, IAggregateRoot
{
public string Name { get; set; }
public string Dimension { get; set; }
public decimal Volume { get; set; }
public bool Featured { get; set; }
public Farm Farm { get; set; }
public int FarmId { get; set; }
/// <summary>
/// Sell Price
/// </summary>
public decimal BidPrice { get; set; }
public int QuantityAvaliable { get; set; }
public ICollection<Image> Images { get; set; }
public string Description { get; set; }
public Category Category { get; set; }
public int CategoryId { get; set; }
public DateTime Created { get; set; }
public DateTime? Modified { get; set; }
}
public class Category : Entity, IAggregateRoot
{
public string Title { get; set; }
public string CategoryImage { get; set; }
public Category Parent { get; set; }
public DateTime Created { get; set; }
public DateTime? Modified { get; set; }
}
Relationship setup
public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
HasKey(x => x.Id);
Property(x => x.Created).HasColumnType("DateTime");
Property(x => x.Modified).HasColumnType("DateTime");
Property(x => x.BidPrice).HasColumnType("Decimal");
#region RELATIONSHIP
//BelongsTo
HasRequired(x => x.Farm);
HasRequired(x => x.Category);
HasMany(x => x.Images);
#endregion
}
So I have this two model where I need to bring the data from Product model with Category information
I have checked my database, the data is consistent, the Product record have the FK for the Category record.
but when I try to get Product Data using EF6, the category information doesnt come, I get a null object.
Because of = () =>
{
_product = _repository.Find(p => p.Id == 1, p => p.Category);
};
It should_not_be_bull = () =>
_product.Category.ShouldNotBeNull();
the response from data base is for Category is null. but the record is there.
I had it working properly before. for some random magic reason it just stop working.
THE FIND method
public virtual TEntity Find(Expression<Func<TEntity, bool>> predicate = null, params Expression<Func<TEntity, object>>[] includes)
{
var set = CreateIncludedSet(includes);
return (predicate == null) ?
set.FirstOrDefault() :
set.FirstOrDefault(predicate);
}
the CreateIncludeSet
private IDbSet<TEntity> CreateIncludedSet(IEnumerable<Expression<Func<TEntity, object>>> includes)
{
var set = CreateSet();
if (includes != null)
{
foreach (var include in includes)
{
set.Include(include);
}
}
return set;
}
the CreateSet method
private IDbSet<TEntity> CreateSet()
{
return Context.CreateSet<TEntity>();
}
MY DbContext implementation is here
https://github.com/RobsonKarls/FreedomWebApi/blob/dev/Source/Freedom.Infrastructure.DataAccess/Factories/FreedomDbContext.cs
all project is there too for further analisys
any help is valuable.
Thank you
The problem in your code is in this line in CreateIncludedSet method:
set.Include(include);
Yes, you include the data but you do not change you set. You should change it to something like:
set = set.Include(include);
Your code is a bit unclear, but try something like this....
_product = _repository.Include(p => p.Category).SingleOrDefault(x => x.Id == 1);
also see...
https://stackoverflow.com/a/7348694/6200410
I'm using EF 6 and defining my database with Code First.
The following line of code returns a Transaction entity, however the EndorsementInfo navigation property is null. I've checked the database and there is definitely data for the test data. "var trans" does appear to have a valid IQueryable, but navigation property t.EndorsementInfo is null when it shouldn't be.
var trans = unitOfWork.GetRepository<Transaction>().GetAll().Where(t => t.PolicyId == command.PolicyId);
results.Transactions = new List<TransactionListItem>();
foreach (var t in trans)
{
results.Transactions.Add(new TransactionListItem
{
Id = t.Id,
EffDate = t.EffectiveDate,
EffectiveDate = t.EffectiveDate.ToShortDateString(),
TransactionType = t.TransactionType.ToStringValue(),
EndorsementType = t.TransactionType == TransactionType.Endorsement ?
t.EndorsementInfo.EndorsementType.Description : ""
});
}
Transaction Entity:
public class Transaction : EntityBase
{
[Required]
public TransactionType TransactionType { get; set; }
public long PolicyId { get; set; }
public virtual Policy Policy { get; set; }
[Required]
public DateTime EffectiveDate { get; set; }
public DateTime? ExpirationDate { get; set; }
public string Description { get; set; }
public virtual Quote QuoteInfo { get; set; }
public virtual Cancellation CancellationInfo { get; set; }
public virtual NewBusiness NewBusinessInfo { get; set; }
public virtual Endorsement EndorsementInfo { get; set; }
}
Endorsement Entity
public class Endorsement : EntityBase
{
public Transaction Transaction { get; set; }
public long EndorsementTypeId { get; set; }
public virtual EndorsementType EndorsementType { get; set; }
public int EndorsementNum { get; set; }
[MaxLength(500)]
public string EndorsementDesc { get; set; }
public Decimal? Premium { get; set; }
}
Code First Fluent Configurations
public class TransactionConfiguration : EntityTypeConfiguration<Transaction>
{
public TransactionConfiguration()
{
HasOptional(t => t.QuoteInfo).WithRequired(q => q.Transaction);
HasOptional(t => t.NewBusinessInfo).WithRequired(q => q.Transaction);
HasOptional(t => t.EndorsementInfo).WithRequired(q => q.Transaction);
HasOptional(t => t.CancellationInfo).WithRequired(q => q.Transaction);
}
}
Repositories implementation of GetAll
public IQueryable<T> GetAll(string include)
{
return _set.Include(include);
}
I've checked and rechecked that everything is set up correctly. I don't know what I could be missing.
Thanks.
You are using an opened connection to execute two data readers, you need to enable the multiple result set in the connection string.
MultipleActiveResultSets=True;
I have a User that can have collection of users he likes...
Another user can have collection of users he likes....
If User A likes User B and if User B likes User A, then they get to hang out. I need to send each other their contact info. How do we represent such a model in Entity Framework Code First?
public class User
{
public int UserId { get; set; }
public int? UserLikeId { get; set; }
public virtual UserLike UserLike { get; set; }
}
public class UserLike
{
public int UserLikeId { get; set; }
public int UserId { get; set; }
public virtual User User { get; set; }
public virtual ICollection<User> LikeUsers { get; set; }
}
Is this model correct? I can't get this to work.
I've tried another way but that doesn't work too...
I tried to add collection of user to user table.
For ex :
public virtual ICollection<User> userlike { get; set; }
public class User
{
public int UserId { get; set; }
public virtual ICollection<UserLike> UserLikes { get; set; }
}
public class UserLike
{
public int UserLikeId { get; set; }
public int UserId { get; set; }
public virtual User User { get; set; }
public int LikeUserId { get; set; }
public virtual User LikeUser { get; set; }
}
I get this error when I try to add user and who they like:
Conflicting changes to the role 'UserLike_LikeUser_Target' of the relationship 'UserLike_LikeUser' have been detected.
What's the best way to represent such a model?
You don't really need a separate entity to describe the relationship, the object model below will do the trick:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public int? ThisUserLikesId { get; set; }
public virtual User ThisUserLikes { get; set; }
public virtual ICollection<User> LikeThisUser { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(u => u.ThisUserLikes)
.WithMany(u => u.LikeThisUser)
.HasForeignKey(u => u.ThisUserLikesId);
}
}
Now let's say you have a UserId in your hand and want to find the other User who likes this user which this user also like him:
using (var context = new Context())
{
// For a given user id = 1
var friends = (from u in context.Users
where u.UserId == 1
from v in u.LikeThisUser
where v.UserId == u.ThisUserLikesId
select new
{
OurUser = u,
HerFriend = v
})
.SingleOrDefault();
ExchangeContactInfo(friends.OurUser, friends.HerFriend);
}
Update 1:
A self referencing many-to-many association will be mapped to database using a join table which require a different object model and fluent API altogether:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<User> ThisUserLikes { get; set; }
public virtual ICollection<User> UsersLikeThisUser { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(u => u.ThisUserLikes)
.WithMany(u => u.UsersLikeThisUser)
.Map(c =>
{
c.MapLeftKey("UserId");
c.MapRightKey("OtherUserId");
c.ToTable("UserLikes");
});
}
}
Update 2:
As I explained in this post, a many-to-many association cannot have a payload (e.g EventId), and if that’s the case then we have to break it down to two one-to-many associations to an intervening class and I can see you’ve correctly created this class (UserLike) to represent the extra information attached to your self-referencing many-to-many association but the associations from this intermediate class are not correct as we need to define exactly 2 many-to-one association from UserLike to User like I showed in the following object model:
public class User
{
public int UserId { get; set; }
public string Email { get; set; }
public virtual ICollection ThisUserLikes { get; set; }
public virtual ICollection UsersLikeThisUser { get; set; }
}
public class UserLike
{
public int UserLikeId { get; set; }
public int LikerId { get; set; }
public int LikeeId { get; set; }
public int EventId { get; set; }
public User Liker { get; set; }
public User Likee { get; set; }
public virtual Event Event { get; set; }
}
public class Event
{
public int EventId { get; set; }
public string Name { get; set; }
}
public class Context : DbContext
{
public DbSet Users { get; set; }
public DbSet Events { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasMany(u => u.ThisUserLikes)
.WithRequired(ul => ul.Liker)
.HasForeignKey(ul => ul.LikerId);
modelBuilder.Entity()
.HasMany(u => u.UsersLikeThisUser)
.WithRequired(ul => ul.Likee)
.HasForeignKey(ul => ul.LikeeId)
.WillCascadeOnDelete(false);
}
}
Now you can use the following LINQ query to retrieve all the users who like each other:
using (var context = new Context())
{
var friends = (from u1 in context.Users
from likers in u1.UsersLikeThisUser
from u2 in u1.ThisUserLikes
where u2.LikeeId == likers.LikerId
select new
{
OurUser = u1.UserId,
HerFriend = u2.LikeeId
})
.ToList();
}
Hope this helps.