Just playing around with entity framework.
Now I have a simple database, containing to Entities
Person (Id, Name)
Profession (Id, Designation)
which has an association on the Id.
I want to give a person a new profession programatically with this code:
using (PersonDataModelContainer dmc = new PersonDataModelContainer())
{
var pers = new Person() { Id = PersonId };
dmc.Person.Attach(pers);
var prof = new Profession() { Id = ProfessionId };
dmc.Profession.Attach(prof);
pers.Professions.Add(req);
var result = dmc.SaveChanges();
return (result > 0);
};
I'm quite new to EF, so it is possibly quite simple.
the effect is: nothing happens and I do not see any
new Association in the associations table.
How can I add a new association from existing entities?
Is there any good documentation on working with that concept?
-edit-
found a copy of the database in the bin\debug folder.
It doesn't contain associations either. but there seems
to be writes to that file each time I fire the update as
in the code above.
I guess you should to use this SQL Compact, Identity Columns and Entity Framework
using (var con = new PersonDataModelContainer())
{
var pers = new Person() { Id = PersonId };
int pId = 0;
if (pers.PersonId > 0)
{
pers = con.Persons.FirstOrDefault(c => c.PersonId == pers.PersonId);
pId = pers.pId;
}
else
pId = con.Users.NextId(c => c.PersonId) + 1;
if (pers.UserId == 0)
con.Persons.AddObject(pers);
con.SaveChanges();
pId = Persons.PersonId;
var prof = new Profession() { Id = ProfessionId, PersonId = pId };
int profId = 0;
if (prof.PersonId > 0)
{
prof = con.Professions.FirstOrDefault(c => c.ProfessionId == prof.ProfessionId);
profId = prof.PersonId;
}
else
profId = con.Professions.NextId(c => c.ProfessionId) + 1;
if (prof.ProfessionId == 0)
con.Professions.AddObject(prof);
con.SaveChanges();
prof.ProfessionId = profId;
}
This should work:
using (PersonDataModelContainer dmc = new PersonDataModelContainer())
{
var pers = new Person() { Id = PersonId };
var prof = new Profession() { Id = ProfessionId };
pers.Professions.Add(prof);
dmc.Persons.Add(pers);
var result = dmc.SaveChanges();
}
Seem to have found the problem:
In the connection string I have |DataPath| which is set to the copy
at runtime.
Setting the DataPath to the actual path at the beginning of the Main function,
everything seems to be fine
This can be achieved with
AppDomain.CurrentDomain.SetData("DataDirectory", #"C:\myDB");
where C:\myDB is the path where the sdl file lives.
At the moment I have no idea, what to do about that on deployment, perhaps
it is enough to just comment out that line then, having the deploy path
as database path.
Related
This code saves my data to the database. The app records the time spent on each day of the month.
They write to the database in SQL Server, using EF. The problem is just that I would like them to overwrite instead of writing more
Controller:
List<Karta_Model> objNextKartaModel = new List<Karta_Model>();
for (int i = 0; i < liczbaDni; i++)
{
var modelNext = new Karta_Model()
{
Login = userName,
Rok = numerRoku,
Miesiac = numerMiesiaca,
DzMiesiaca = modelKarta.Model1[i].DzMiesiaca.Value,
DzTygodnia = modelKarta.Model1[i].DzTygodnia,
Rozpoczecie = modelKarta.Model1[i].Rozpoczecie
....
};
objNextKartaModel.Add(modelNext);
await _ecpContext.Karta.AddRangeAsync(objNextKartaModel);
await _ecpContext.SaveChangesAsync();
}
Id in SQL Server is defined as:
[Id] [int] IDENTITY(1,1)
I came up with the idea to extract the first row ID from the previously saved database
var nrIdBase = _ecpContext.Karta
.FirstOrDefault(f => f.DzMiesiaca == 1 &&
f.Miesiac == numerMiesiaca &&
f.Rok == numerRoku &&
f.Login == userName).Id;
but I don't know how to use it.
I tried something like this:
for (int i = 0; i < liczbaDni; i++)
{
var modelNext = new Karta_Model()
{
Id = nrIdBase +i,
Login = userName,
Rok = numerRoku,
Miesiac = numerMiesiaca,
DzMiesiaca = modelKarta.Model1[i].DzMiesiaca.Value,
DzTygodnia = modelKarta.Model1[i].DzTygodnia,
Rozpoczecie = modelKarta.Model1[i].Rozpoczecie
....
};
}
but I get an error:
InvalidOperationException: The instance of entity type 'Karta_Model' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
Does anyone have an idea how to do this?
How to overwrite saved data once?
In order to update an existing recording in a database, you need to have it's ID before the update operation.
Then you can do this:
var existingRecord = _ecpContext.Karta.FirstOrDefault(x => x.Id == theExistingId);
if (existingRecord != null) {
existingRecord.Login = "CHANGED";
await _ecpContext.SaveChangesAsync()
}
This call that you are using:
await _ecpContext.Karta.AddRangeAsync(objNextKartaModel);
Is only for adding new items to the database.
Following the idea in my comment above, one thing you can do is to delete the existing data in the table before adding the new ones.
List<Karta_Model> objNextKartaModel = new List<Karta_Model>();
for (int i = 0; i < liczbaDni; i++)
{
var modelNext = new Karta_Model()
{
Login = userName,
Rok = numerRoku,
Miesiac = numerMiesiaca,
DzMiesiaca = modelKarta.Model1[i].DzMiesiaca.Value,
DzTygodnia = modelKarta.Model1[i].DzTygodnia,
Rozpoczecie = modelKarta.Model1[i].Rozpoczecie
....
};
objNextKartaModel.Add(modelNext);
//Add logic to delete the existing data
foreach(var model in _ecpContext.Karta)
{
_ecpContext.Karta.Remove(model);
}
await _ecpContext.Karta.AddRangeAsync(objNextKartaModel);
await _ecpContext.SaveChangesAsync();//One SaveChanges call is enough to update the database
}
I have following methods:
Controller:
...
var appmap = Services.GetReqAppMapList(value);
var applist = Services.GetApplicationList(docid, appid, reqid, appmap);
...
Model:
public static IEnumerable<AppMap> GetReqAppMapList(int aiRequestTypeId)
{
try
{
var appmap = new List<AppMap>();
using (var eties = new eRequestsEntities())
{
appmap = (from ram in eties.ReqAppMaps
where ram.IsActive == 1
select new AppMap
{
RequestTypeId = ram.RequestTypeId
}).ToList();
return appmap;
}
}
catch(Exception e)
{
throw e;
}
}
public static IEnumerable<TicketApplication> GetApplicationList(int aiDocumentTypeId, int aiApplicationTypeId, int aiRequestTypeId, IEnumerable<AppMap> appmap)
{
try
{
var applicationlist = new List<TicketApplication>();
using (var applicationentity = new eRequestsEntities())
{
applicationlist = (from app in applicationentity.Applications
where 1==1
<<<Some Conditions Here???>>>
== && appmap.Contains(app.ApplicationTypeId) ==
&& app.IsActive == 1
select new TicketApplication
{
ApplicationId = app.ApplicationId,
Description = app.Description,
DeliveryGroupId = app.DeliveryGroupId,
ApplicationTypeId = app.ApplicationTypeId,
DeliveryTypeId = app.DeliveryTypeId,
DocumentTypeId = app.DocumentTypeId,
SupportGroupId = app.SupportGroupId
}).OrderBy(a => a.Description).ToList();
return applicationlist;
}
And I was thinking how can filter query result of GetApplicationList using the result from GetReqAppMapList
I'm kinda stuck with the fact that I must convert/cast something to the correct type because every time I do a result.Contains (appmap.Contains to be exact), I always get the following error
Error 4 Instance argument: cannot convert from
'System.Collections.Generic.IEnumerable<Test.Models.AppMap>' to
'System.Linq.ParallelQuery<int?>'
You should directly join the two tables in one query.
using (var applicationentity = new eRequestsEntities())
{
applicationlist = (from app in applicationentity.Applications
join ram in applicationentity.ReqAppMaps on app.ApplicationTypeId equals ram.RequestTypeId
where ram.IsActive == 1 && app.IsActive == 1
select new TicketApplication
{
ApplicationId = app.ApplicationId,
Description = app.Description,
DeliveryGroupId = app.DeliveryGroupId,
ApplicationTypeId = app.ApplicationTypeId,
DeliveryTypeId = app.DeliveryTypeId,
DocumentTypeId = app.DocumentTypeId,
SupportGroupId = app.SupportGroupId
}).OrderBy(a => a.Description).ToList();
You can delete the other method if it is not needed anymore. No point hanging onto code which is dead.
Looks like there is no other way to do this (as far as I know), so I have to refactor the code, I hope still that there would be a straight forward conversion and matching method in the future (too lazy). Anyway, please see below for my solution. Hope this helps someone with the same problem in the future. I'm not sure about the performance, but this should work for now.
Controller:
...
var appmap = Services.GetReqAppMapList(value);
var applist = Services.GetApplicationList(docid, appid, reqid, appmap);
...
Model:
<Removed GetReqAppMapList>--bad idea
public static IEnumerable<TicketApplication> GetApplicationList(int aiDocumentTypeId, int aiApplicationTypeId, int aiRequestTypeId)
{
try
{
//This is the magic potion...
List<int?> appmap = new List<int?>();
var applist = (from ram in applicationentity.ReqAppMaps
where ram.RequestTypeId == aiRequestTypeId
&& ram.IsActive == 1
select new AppMap
{
ApplicationTypeId = ram.ApplicationTypeId
}).ToList();
foreach (var item in applist)
{
appmap.Add(item.ApplicationTypeId);
}
//magic potion end
var applicationlist = new List<TicketApplication>();
using (var applicationentity = new eRequestsEntities())
{
applicationlist = (from app in applicationentity.Applications
where 1==1
===>>>&& appmap.Contains(app.ApplicationTypeId)<<<===
&& app.IsActive == 1
select new TicketApplication
{
ApplicationId = app.ApplicationId,
Description = app.Description,
DeliveryGroupId = app.DeliveryGroupId,
ApplicationTypeId =app.ApplicationTypeId,
DeliveryTypeId = app.DeliveryTypeId,
DocumentTypeId = app.DocumentTypeId,
SupportGroupId = app.SupportGroupId
}).OrderBy(a => a.Description).ToList();
return applicationlist;
}
A side-note, C# is a strongly-typed language, just make sure your data types matches during evaluation, as int? vs int etc.., will never compile. A small dose of LINQ is enough to send some newbies circling around for hours. One of my ID-10T programming experience but just enough to remind me that my feet's still flat on the ground.
I have a question about using a generic method with the entity framework.
I am using this example model
Data Model
And this is the code in my webform this code to populate the object.
var user = new User();
var selectedTitles = new List<UserTitle>();
var selectedDisabilities = new List<UserDisability>();
var t = titleRepository.SearchFor(d => d.Id==1 || d.Id ==2);
foreach (var temp in t)
{
selectedTitles.Add(new UserTitle { IsPublic = true, Title = temp, User = user });
}
var ds = disabilityRepository.SearchFor(d => d.Id==1 || d.Id ==2);
foreach (var temp in ds)
{
selectedDisabilities.Add(new UserDisability { IsPublic = true, Disability = temp, User = user });
}
user.FirstName = "Johnathan";
user.LastName = "Rifkin";
user.UserTitles = selectedTitles;
user.UserDisabilities = selectedDisabilities;
userRepository.Insert(user);
As you can see when populating the “UserTitles” and “UserDisabilities” properties the code is very similar, so rather than duplicate the code I would like to create a generic method that I can use to populate both the “UserTitles” and “UserDisabilities” and any other properties that I'll need in future.
Thanks in advance
I'm trying to insert some data in my database using Entity Framework model, but for some unknown reasons to me, it does nothing.
Am I missing something here?
using (var context = new DatabaseEntities())
{
var t = new test
{
ID = Guid.NewGuid(),
name = "blah",
};
context.AddTotest(t);
context.SaveChanges();
}
It should be:
context.TableName.Add(TableEntityInstance);
For versions of entity framework before 6, it was:
context.TableName.AddObject(TableEntityInstance);
Where:
TableName: the name of the table in the database.
TableEntityInstance: an instance of the table entity class.
If your table is Orders, then:
Order order = new Order();
context.Orders.Add(order);
For example:
var id = Guid.NewGuid();
// insert
using (var db = new EfContext("name=EfSample"))
{
var customers = db.Set<Customer>();
customers.Add( new Customer { CustomerId = id, Name = "John Doe" } );
db.SaveChanges();
}
Here is an example:
public void UpdatePlayerScreen(byte[] imageBytes, string installationKey)
{
var player = (from p in this.ObjectContext.Players where p.InstallationKey == installationKey select p).FirstOrDefault();
var current = (from d in this.ObjectContext.Screenshots where d.PlayerID == player.ID select d).FirstOrDefault();
if (current != null)
{
current.Screen = imageBytes;
current.Refreshed = DateTime.Now;
this.ObjectContext.SaveChanges();
}
else
{
Screenshot screenshot = new Screenshot();
screenshot.ID = Guid.NewGuid();
screenshot.Interval = 1000;
screenshot.IsTurnedOn = true;
screenshot.PlayerID = player.ID;
screenshot.Refreshed = DateTime.Now;
screenshot.Screen = imageBytes;
this.ObjectContext.Screenshots.Add(screenshot);
this.ObjectContext.SaveChanges();
}
}
var context = new DatabaseEntities();
var t = new test //Make sure you have a table called test in DB
{
ID = Guid.NewGuid(),
name = "blah",
};
context.test.Add(t);
context.SaveChanges();
Should do it
[HttpPost] // it use when you write logic on button click event
public ActionResult DemoInsert(EmployeeModel emp)
{
Employee emptbl = new Employee(); // make object of table
emptbl.EmpName = emp.EmpName;
emptbl.EmpAddress = emp.EmpAddress; // add if any field you want insert
dbc.Employees.Add(emptbl); // pass the table object
dbc.SaveChanges();
return View();
}
When I run the code below, it works
int charId = int.Parse(Request.Params["charId"]);
EveFPT ctx = new EveFPT();
var theCharQuery = from a in ctx.tblChars
where a.id == charId
select new
{
Name = a.name,
CorpName = a.tblCorps.name,
AllianceName = a.tblCorps.tblAlliances.name
};
if(theCharQuery.Count() == 1)
{
var theChar = theCharQuery.First();
lblCharName.Text = theChar.Name;
lblCorpName.Text = theChar.CorpName;
lblAllianceName.Text = theChar.AllianceName;
}
However, If I the below
var theCharQuery = from a in ctx.tblChars
where a.id == charId
select a;
if(theCharQuery.Count() == 1)
{
tblChars theChar = theCharQuery.First();
lblCharName.Text = theChar.name;
lblCorpName.Text = theChar.tblCorps.name;
lblAllianceName.Text = theChar.tblCorps.tblAlliances.name;
}
the statement
theChar.tblCorps
always returns null. Anyone know what's happening?
The Entity Framework doesn't eagerly load child object. You have to check if they're loaded, and then call Load() if they're not.
if(!theChar.tblCorps.IsLoaded)
{
theChar.tblCorps.Load();
}
Here's a good read from MSDN on the subject:
How to: Explicity Load Related Objects (Entity Framework)
I was thinking the same thing, although I wouldn't have expected it to eagerly load in the first example's projection expression either. Once way to try it:
var charId= int.Parse(Request.Params["charId"]);
EveFPT ctx = new EveFPT();
var theChar = ( from a in ctx.tblChars.Include ( "tblCorps" )
where a.id == charId
select new
{
Name = a.name,
CorpName = a.tblCorps.name,
AllianceName = a.tblCorps.tblAlliances.name
} ).FirstOrDefault ();
if(theChar != null)
{
lblCharName.Text = theChar.Name;
lblCorpName.Text = theChar.CorpName;
lblAllianceName.Text = theChar.AllianceName;
}