Entity Framework Adding Child Objects to DB - c#

I am currently stuck on adding a new child entity to my database using lamda queries.
The structure of my database is that Area has a one to many relationship with
Shifts
In my seeding database I populate the Shifts while creating the Areas:
new Area()
{
AreaDesc = "Area 1",
AreaActive = true,
AreaCreatedDate = DateTime.Now,
SHFID = new Shift()
{
StartTime = new TimeSpan (5,30,00),
EndTime = new TimeSpan (11, 00, 00),
RequiredResources = 2,
ShiftDesc = "AM Shift",
ShiftDayID = 1
}
}
That works fine, where I am struggling and probably due to a simple lack of understanding on entity frameworks abilities is adding a new Shift to an existing Area.
So far I have the following
var AreaVal = _context.Areas.Where(a => a.AreaID == AreaID).ToList();
var Shift = new Shift
{
Area = AreaVal,
StartTime = StartTime,
EndTime = EndTime,
ShiftDayID = model.ShiftDayID,
ShiftDesc = model.ShiftDesc
};
Thinking that once I had the correct Area (I have the ID coming from the model) I could load the Area and pass it as the Area parameter in the Shift and entity framework would know what to do.
The Error I get in the parser is:
Cannot implicitly convert type (Generic.List to
Models.Area.
I have also considered going from the other direction using _context.Areas.Update() but have been unable to work that one out very well.
Extra Info, Model Structures
Shift.cs
public class Shift
{
[Key]
public int SHFID { get; set; }
public TimeSpan StartTime { get; set; }
public TimeSpan EndTime { get; set; }
public int RequiredResources { get; set; }
public string ShiftDesc { get; set; }
public int ShiftDayID { get; set; }
public DateTime ShiftExDateStart { get; set; }
public DateTime ShiftExDateEnd { get; set; }
public int ShiftExLevel { get; set; }
public TimeSpan ShiftExStartTime { get; set; }
public TimeSpan ShiftExEndTime { get; set; }
public Area Area { get; set; }
}
Area.cs
public class Area
{
[Key]
public int AreaID { get; set; }
public string AreaDesc { get; set; }
public Boolean AreaActive { get; set; }
public DateTime AreaCreatedDate { get; set; }
public List<Shift> SHFID { get; set; }
public Company Company { get; set;}
}

You are on the right track.
AreaVal needs to be a single entity (Area), not a list of entities (List<Area>). Then it should work as expected.
Change the line:
var AreaVal = _context.Areas.Where(a => a.AreaID == AreaID).ToList();
to
var AreaVal = _context.Areas.Where(a => a.AreaID == AreaID).Single();

Related

One to zero or one relationship Entity Framework, getting the relation of an entity

I'm trying to establish a one to zero or one relationship in EF Core, but I can't seem to go into a model and get it's related model.
public class Voucher
{
[Key]
public long id { get; set; }
public long voucherId { get; set; }
public long number { get; set; }
public string Type { get; set; }
public string description { get; set; }
public DateTime date { get; set; }
public int paymentId { get; set; }
public Invoice invoice { get; set; }
[ForeignKey("client")]
public long clientFK { get; set; }
public Client client { get; set; }
public ICollection<Post> posts { get; set; } = new List<Post>();
}
public class Invoice
{
[Key, ForeignKey("voucher")]
public long voucherFK { get; set; }
public long invoiceId { get; set; }
public string clientId { get; set; }
public DateTime dueDate { get; set; }
public decimal amountTotal { get; set; }
public string specification { get; set; }
public string invoicePdf { get; set; }
public long orderId { get; set; }
public Voucher voucher { get; set; }
public ICollection<InvoiceLine> invoiceLines { get; set; } = new List<InvoiceLine>();
}
Now I can create Vouchers without the need for an invoice, and unnable to create an invoice without a voucher. (I've also tried several other ways to map this relationship)
The problem is when I'm trying to fetch invoices that are bound to vouchers or the other way around.
Here's an example of how I tried to do it:
[HttpGet("testing1")]
public List<Voucher> getInvoiceTest(string filter)
{
long tenantId = getTenantId();
DateTime comparisonDate = compareDates(filter);
var invoices = _warehouseDb.Invoices
.Where(v => v.voucher.client.tenantFK == tenantId)
.Where(d => d.voucher.date >= comparisonDate)
.OrderByDescending(p => p.voucher.paymentId).ThenByDescending(d => d.voucher.date)
.ToList();
//return invoices;
List<Voucher> vouchers = new List<Voucher>();
for (int i = 0; i < invoices.Count - 1; i++)
{
if (invoices[i].voucher != null)
{
Console.WriteLine("i value: " + i);
Voucher voucher = new Voucher();
voucher = invoices[i].voucher;
vouchers.Add(voucher);
}
}
return vouchers;
}
I've tried without the ending forloop to see if I actually get a list of invoices, and I do. The filter part is just to get it within the correct time-span.
Once I reach the forloop, it can't seem to get any vouchers connected to any of the invoices.
Have I connected the models wrong or what's going on? This exact type of code works for other models where the relationship is one-to-many.
I've also tried mapping the models with virtual tag to see if it made any difference. I also had invoices save a FK for vouchers, but my main goal is to go through a list of vouchers and get it's invoice.
Any suggestion is appreciated, if not, thanks for reading.
I'm using Entity framework core and postgreSQL

Handling Nested Objects in Entity Framework

I am struggling a bit to wrap my head around Entity Framework and It's driving me crazy. I have an target object that I'd like to populate:
public class ApiInvitationModel
{
public int Id { get; set; }
public EventModel Event { get; set; }
public UserModel InvitationSentTo { get; set; }
public UserModel AttendingUser { get; set; }
}
The schemas of the above models are:
public class EventModel {
public int Id? { get; set; }
public string Name { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set }
public OrganizationModel HostingOrganization { get; set; }
public Venue Venue { get; set; }
public string Price { get; set; }
}
public class UserModel {
public int Id? { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
public string MobileNumber { get; set; }
public List<OrganizationModel> Organizations { get; set; }
}
public class OrganizationModel {
public int Id? { get; set; }
public stirng Name { get; set; }
public string Address { get; set; }
public UserModel PrimaryContact { get; set; }
}
The above schemas are simplified for the purpose of the question and are the models we intend to return via API.
The problem is the origin schemas in the database is very different and I'm trying to map the database objects to these objects via Entity Framework 6.
My attempted solution was to try and nest the models via a query but that didn't work and I'm not sure where to go from here besides making numerous calls to the database.
public List<ApiInvitationModel> GetInvitations(int userId) {
using (var entities = new Entities()) {
return entities.EventInvitations
.Join(entities.Users, invitation => invitiation.userId, user => user.id, (invitation, user) => new {invitation, user})
.Join(entities.Events, model => model.invitation.eventId, ev => ev.id, (model, ev) => new {model.invitation, model.user, ev})
.Join(entities.organization, model => model.user.organizationId, organization => organization.id, (model, organization) => new ApiInvitationModel
{
Id = model.invitation.id,
Event = new EventModel {
Id = model.event.id,
Name = model.event.name,
StartDate = model.event.startDate,
EndDate = model.event.endDate,
HostingOrganization = new OrganizationModel {
Id = model.invitation.hostingId,
Name = model.event.venueName,
Address = model.event.address,
PrimaryContact = new UserModel {
Name = model.event.contactName,
PhoneNumber = model.event.contactNumber,
}
}
...
},
InvitedUser = {
}
}
).ToList();
}
}
As you can see above, there's quite a bit of nesting going on but this doesn't work in Entity Framework 6 as far as I am aware. I keep getting the following errors:
"The type 'Entities.Models.API.UserModel' appears in two structurally incompatible initializations within a single LINQ to Entities query. A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.",
Based on the above error, I assumed that each of the model initiatilizations would need to be the same (i.e. initializing the values as the same ApiInvitationModel in each join in the same order) but that produces the same error.
What would be the best approach to handling this, keepign in mind the source database doesn't have foreign keys implemented?

EF6 Code First, Store update, insert, or delete statement affected an unexpected number of rows (0)

I'm having some troubles getting EntityFramework to do what I want. I have an object and I want to keep track of the current and previous state. So when there is an update the previous state will than be changed to the current state and the current state becomes a new object like this:
using (var db = new DBContext())
{
var currentPair = await db.CurrencyPairs.Include(c => c.CurrentRate).Include(c => c.PreviousRate).SingleAsync(p => p.CurrencyPairId == pair.CurrencyPairId);
var newRate = new ExchangeRate()
{
CurrencyPairId = currentPair.CurrencyPairId,
HighestBid = t.HighestBid,
LowestAsk = t.LowestAsk,
Last = t.LastPrice,
Volume = t.DailyVolume,
UpdateTime = DateTime.UtcNow
};
if (currentPair.AveragePrice == null || (DateTime.UtcNow - DateTime.Parse(db.Store.Single(s => s.Key == "CurrentStartTime").Value)).TotalHours < 4)
currentPair.AveragePrice = (t.DailyHigh + t.DailyLow) / 2;
currentPair.PreviousRate = currentPair.CurrentRate;
currentPair.CurrentRate = newRate;
await db.SaveChangesAsync();
}
The problem is that I'm getting an EntityFramework error when saving:
Store update, insert, or delete statement affected an unexpected
number of rows (0). Entities may have been modified or deleted since
entities were loaded.
The ExchangeRate object has an identity column so the ID should get filled automatically. This thread is the only one that is setting the CurrentRate/PreviousRate properties, there are other threads that read them.
Anyone has a clue as to what I'm doing wrong?
EDIT: ExchangeRate object
public class ExchangeRate
{
[Key]
public long ExhangeRateId { get; set; }
public double HighestBid { get; set; }
public double LowestAsk { get; set; }
public double Volume { get; set; }
public double Last { get; set; }
public DateTime UpdateTime { get; set; }
public long CurrencyPairId { get; set; }
}
You forget to add reference property to CurrencyPair. One foreign key id is not enough.
public class ExchangeRate
{
[Key]
public long ExhangeRateId { get; set; }
public double HighestBid { get; set; }
public double LowestAsk { get; set; }
public double Volume { get; set; }
public double Last { get; set; }
public DateTime UpdateTime { get; set; }
public long CurrencyPairId { get; set; }
public virtual CurrencyPair CurrencyPair { get; set; }
}
Here is some docs article

Understanding MongoDb .NET driver indexing

I'm currently working on an application where MongoDb is used for quite a large amount of data.
The objects I'm storing in MongoDb looks like this:
public class PowerPlantDataReading
{
[BsonId]
public int ID { get; set; }
[BsonElement("EDIEL")]
public string EDIEL { get; set; }
[BsonElement("EndDate")]
public DateTime EndDate { get; set; }
[BsonElement("Created")]
public DateTime Created { get; set; }
[BsonElement("DataReading")]
public DataReading DataReading { get; set; }
}
public class DataReading
{
[BsonElement("Version")]
public int Version { get; set; }
[BsonElement("OriginalId")]
public int OriginalId { get; set; }
[BsonElement("Unit")]
public string Unit { get; set; }
[BsonRepresentation(MongoDB.Bson.BsonType.Double)]
[BsonElement("Quantity")]
public decimal Quantity { get; set; }
[BsonElement("Quality")]
public string Quality { get; set; }
[BsonElement("StartDate")]
public DateTime StartDate { get; set; }
}
And the query I'm running against MongoDb looks like this:
DateTime startDateUtc = DateTime.UtcNow.AddDays(-5);
DateTime endDateUtc = DateTime.UtcNow;
var queryBuilder = Builders<PowerPlantDataReading>.Filter;
var filter = queryBuilder.Where(x => x.EndDate >= startDateUtc && x.EndDate < endDateUtc);
var query = collection.Find(filter).ToListAsync();
return query.Result;
The query returns around 825.000 objects, but takes well over 4 minutes to run.
I then tried to create an index like this:
IMongoCollection<PowerPlantDataReading> collection = GetCollection();
collection.Indexes.CreateOne(Builders<PowerPlantDataReading>.IndexKeys.Descending(x => x.EndDate));
Then ran the query again, but to my surprise, it didn't make a difference at all.
I'm not sure if I'm creating the index correctly? If not, how should I create my index to get the best possible performance for the query?
Thanks in advance.

How to do nested group by in RavenDB multi map index

I have two different document collections in my RavenDB database - Teams and Matches. The documents look like this:
public class Team {
public string Id { get; set; }
public string Name { get; set; }
public int LeaguePosition { get; set; }
}
public class Match {
public string Id { get; set; }
public string HomeTeamName { get; set; }
public string AwayTeamName { get; set; }
public DateTime StartTime { get; set; }
}
So basically I have teams and matches between these teams. However, for certain operations I need to get an entity which look something like the following from the database:
public class MatchWithExtraData {
public string Id { get; set; } // Id from the match document.
public string HomeTeamId { get; set; }
public string HomeTeamName { get; set; }
public int HomeTeamPosition { get; set; }
public string AwayTeamId { get; set; }
public string AwayTeamName { get; set; }
public int AwayTeamPosition { get; set; }
public DateTime? StartTime { get; set; }
}
What I want is really the match document but with extra fields for the home and away teams' ids and league positions. Basically join the match document on home and away team name with two team documents, one for the home team and one for the away team. I figured that a multi map/reduce index should do the trick so I have started with the following index:
public class MatchWithExtraDataIndex: AbstractMultiMapIndexCreationTask<MatchWithExtraData> {
public MatchWithExtraData() {
AddMap<Team>(
teams => from team in teams
select new {
Id = (string)null,
HomeTeamId = team.Id,
HomeTeamName = team.Name,
HomeTeamPosition = team.LeaguePosition,
AwayTeamId = team.Id,
AwayTeamName = team.Name,
AwayTeamPosition = team.LeaguePosition,
StartTime = (DateTime?)null
}
);
AddMap<Match>(
matches => from match in matches
select new {
Id = match.Id,
HomeTeamId = (string)null,
HomeTeamName = match.HomeTeamName,
HomeTeamPosition = 0,
AwayTeamId = (string)null,
AwayTeamName = match.AwayTeamName,
AwayTeamPosition = 0,
StartTime = match.StartTime
}
);
Reduce = results => from result in results
// NOW WHAT?
}
}
The reduce part is the one I can't figure out since there are two teams in each match. I think I need to do a nested group by, first on the HomeTeamName, and then on the AwayTeamName but I can't figure out how to do that.
Maybe this is more a LINQ problem than a RavenDB problem. But how would such a nested group by statement look? Or could it be done in another way?
You are better off using Transform Results for that, or includes.
See the docs here: http://ravendb.net/docs/client-api/querying/handling-document-relationships

Categories