As the title says, I have a problem writing to local database. I generated a edmx Model from this, and I can easily read from it.
EDMXNS.TOWDataBasev1Entities db = new EDMXNS.TOWDataBasev1Entities();
var query = from p in db.Accounts select p;
foreach (EDMXNS.Accounts s in query)
Console.WriteLine(s.AccountName);
That works fine. However when I try to write to the database, nothing happens. I do not get any errors, exceptions etc. I figure, since I can read from the database, that it's not a connection problem.
Here is the code i have for writing.
EDMXNS.TOWDataBasev1Entities db = new EDMXNS.TOWDataBasev1Entities();
EDMXNS.Accounts acc = new EDMXNS.Accounts();
acc.AccountID = 1;
acc.AccountName = "testuser";
acc.AccountPW = "testpw";
acc.PersonDataID = 0;
db.AddToAccounts(acc);
db.SaveChanges();
It is worthwhile to meantion that my Accounts.AccountID has identity/autoincrement, but I have tried both setting it to the next known value, or simply not setting it at all.
Do anyone have an idea as to what might cause this problem?
EDIT: I also tried to remove the custom name space, delete all records of the database and reimport it all.
Removing the custom tool name space, results in errors like these:
Ambiguity between 'TOWServer.Accounts.AccountName' and 'TOWServer.Accounts.AccountName'
Which doesnt tell me anything.
Reimporting everything now gives me an exception:
"Unable to load the specified metadata resource"
I've always use this format when adding records with EF, Try following this format:
using (MovieStoreEntities context = new MoveStoreEntities())
{
try
{
context.Movies.AddObject(new Movie() { MovieID = 234,
Title = "Sleepless Nights in Seattle", Quantity = 10 });
context.SaveChanges();
}
catch(Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
}
}
Related
I am trying to add an entry into a table and use the primary key of that added entry to create an additional entry into another table.
The error I am getting is
The transaction manager has disabled its support for remote/network
transactions. (Exception from HRESULT: 0x8004D024)
I believe this is caused by creating multiple connections within a single TransactionScope, but I am doing everything within one context / using statement, so I do not believe that I should be receiving this error.
Service
[OperationBehavior(TransactionScopeRequired = true)]
public void CreateGroup(NewGroupData data)
{
var groupRepo = _GroupRepo ?? new InvestigatorGroupRepository();
groupRepo.CreateGroup(data.UserId, data.InvestigatorGroupName, data.HasGameAssignment, data.InstitutionId);
}
Repository
public void CreateGroup(string userId, string investigatorGroupName, bool hasGameAssignment, int institutionId)
{
using (var context = new GameDbContext())
{
var newGroup = new InvestigatorGroup()
{
InvestigatorGroupName = investigatorGroupName,
HasGameAssignment = hasGameAssignment,
InstitutionId = institutionId,
IsTrashed = false
};
int institutionUserId =
context.InstitutionUsers.Where(
iu => !iu.IsTrashed && iu.APUser.UserId == userId && iu.InstitutionId == institutionId).Select(iu => iu.InstitutionUserId).Single();
var newGroupUser = new InvestigatorGroupUser()
{
InstitutionUserId = institutionUserId,
InvestigatorGroup = newGroup,
CreationDate = DateTime.Now
};
context.InvestigatorGroupUsers.Add(newGroupUser);
context.SaveChanges();
}
}
You start with a wrong assumption.
The line...
int newGroupId = context.InvestigatorGroups.Add(newGroup).InvestigatorGroupId;
...will always assign 0 to newGroupId. The Add method only marks the entity for insert, but doesn't actually insert it. Only SaveChanges writes data to the database, not any other method in Entity Framework.
So the assignment...
InvestigatorGroupId = newGroupId,
...is faulty as well. You have to assign the new InvestigatorGroup to a navigation property in InvestigatorGroupUser:
InvestigatorGroup = newGroup,
Add this navigation property to InvestigatorGroupUser if you haven't got it yet.
If you have that, it's enough to execute these lines:
context.InvestigatorGroupUsers.Add(newGroupUser);
context.SaveChanges();
No need to Add the newGroup object too, It will be added by adding newGroupUser.
So if you do that, the only transaction you need is the one that SaveChanges uses internally by default. For the code you show, you don't need a TransactionScope. If this is part of a greater WCF transaction the story may be different, but I think at least you needed some misconceptions to be straightened out.
Update
I think the issue may be that I have my associations set up wrong....some tables are one to one and I have them as one to many...
Im writing a reports program using ironpython C# and linq2sql. The error occurs in the report python file at this code:
#Evaluation Comment Workflow Records
doc.EvaluationCommentworkflowRecords = [];
if (doc.crRecord.V_SOS_CR_EVAL and doc.crRecord.V_SOS_CR_EVAL.V_SOS_WFDSTs.Count > 0):
doc.EvaluationCommentworkflowRecords = doc.crRecord.V_SOS_CR_EVAL.V_SOS_WFDSTs.Where(lambda p: p.DOCTYPE and
p.DOCTYPE == (doc.evalDocType) and
p.ST_DATE).OrderBy(lambda p: p.ST_DATE).ToList()
#End Evaluation Comment Workflow Records
return doc
The error message I get says EntitySet[V_SOS_CR_EVAL] object has no attribute V_SOS_WFDSTs.
But i make the connection in linq2sql with an association and in the dataprovider class:
//evaluation and subs
loadOptions.LoadWith<V_SOS_CR>(p => p.V_SOS_CR_EVAL);
loadOptions.LoadWith<V_SOS_CR_EVAL>(p => p.SOS_ATTs);
loadOptions.LoadWith<V_SOS_CR_EVAL>(p => p.V_SOS_WFDSTs);
and this is the DBML designer.cs file below:
public V_SOS_CR_EVAL()
{
this._SOS_ATTs = new EntitySet<SOS_ATT>(new Action<SOS_ATT>(this.attach_SOS_ATTs), new Action<SOS_ATT>(this.detach_SOS_ATTs));
this._V_SOS_WFDSTs = new EntitySet<V_SOS_WFDST>(new Action<V_SOS_WFDST>(this.attach_V_SOS_WFDSTs), new Action<V_SOS_WFDST>(this.detach_V_SOS_WFDSTs));
this._V_SOS_CR = default(EntityRef<V_SOS_CR>);
OnCreated();
}
then farther down in the code it has:
public V_SOS_WFDST()
{
this._V_SOS_CR = default(EntityRef<V_SOS_CR>);
this._V_SOS_CR_MRULE = default(EntityRef<V_SOS_CR_MRULE>);
this._V_SOS_CR_OPERABILITY = default(EntityRef<V_SOS_CR_OPERABILITY>);
this._V_SOS_CR_REPORTABILITY = default(EntityRef<V_SOS_CR_REPORTABILITY>);
this._V_SOS_CR_EVAL = default(EntityRef<V_SOS_CR_EVAL>);
this._V_SOS_CR_ACTION = default(EntityRef<V_SOS_CR_ACTION>);
OnCreated();
}
If anyone can think of how to fix this error please let me know!
Thanks,
Nick
The problem was in the Associations with the tables. I had many set to one to many when they should have been one to one...
I am trying to write a program to scan a directory containing tv show folders, look up some details about the shows using tvrage API and then save the details to a database using entity framework.
My TVShow table pkey is the same value as taken from the tvrage database show id, and I am having issues when duplicate or similar folder names are returning the same Show info. In a situation where I have a directory containing three folders, "Alias", "Alias 1" , "Band of Brothers" I get the following output from my code
* TV SHOWS *
Alias....... NO MATCH......ADDING........DONE
Alias 1 ...... NO MATCH.....ADDING....CANT ADD, ID ALREADY EXISTS IN DB
Band of Brothers ...... NO MATCH..ADDING....
Before getting an UpdateException on the context.SaveChanges(); line
Violation of PRIMARY KEY constraint 'PK_TVShows'.
I can see using SQL profiler that the problem is that my app is trying to perform an insert on the alias show for a second time with duplicate key, but I can't see why. When I step through the code on the second interaction of the foreach loop (second "alias" folder), the code to save the show entity to the database is bypassed.
It is only on the next iteration of the foreach loop when I have created a new TVShow entity for "Band of Brothers" do I
actually reach the code which adds a Tvshow to context and saves, at which point the app crashes. In visual studio I can see
at the point of the crash that;
"show" entity in context.TVShows.AddObject(show) is "Band of Brothers" w/ a unique ID
context.TVShows only contains one record, the first Alias Entity
But SQL profiler shows that EntityFramework is instead inserting Alias for a second time, and I am stumped by why this is
private void ScanForTVShowFolders( GenreDirectoryInfo drive ) {
IEnumerable<DirectoryInfo> shows = drive.DirInfo.EnumerateDirectories();
foreach (DirectoryInfo d in shows) {
//showList contains a list of existing TV show names previously queried out of DB
if (showList.Contains(d.Name)) {
System.Console.WriteLine(d.Name + ".....MATCH");
} else {
System.Console.Write(d.Name + "......NO MATCH..ADDING....");
TVShow show = LookUpShowOnline(d.Name, drive.GenreName);
if (show.Id == -1) { // id of -1 means online search failed
System.Console.Write("..........CANT FIND SHOW" + Environment.NewLine);
} else if (context.TVShows.Any(a => a.Id == show.Id)) { //catch duplicate primary key insert
System.Console.Write(".......CANT ADD, ID ALREADY EXISTS IN DB" + Environment.NewLine);
} else {
context.TVShows.AddObject(show);
context.SaveChanges();
System.Console.Write("....DONE" + Environment.NewLine);
}
}
}
private TVShow LookUpShowOnline( string name, string genre ) {
string xmlPath = String.Format("http://services.tvrage.com/feeds/search.php?show='{0}'", name);
TVShow aShow = new TVShow();
aShow.Id = -1; // -1 = Can't find
XmlDocument xmlResp = new XmlDocument();
try { xmlResp.Load(xmlPath); } catch (WebException e) { System.Console.WriteLine(e); }
XmlNode root = xmlResp.FirstChild;
if (root.NodeType == XmlNodeType.XmlDeclaration) { root = root.NextSibling; }
XmlNode tvShowXML;
//if (showXML["episode"] == null)
// return false;
tvShowXML = root["show"];
if (tvShowXML != null) {
aShow.Id = System.Convert.ToInt16(tvShowXML["showid"].InnerText);
aShow.Name = tvShowXML["name"].InnerText.Trim();
aShow.StartYear = tvShowXML["started"].InnerText.Trim();
aShow.Status = tvShowXML["status"].InnerText.Trim();
aShow.TVGenre = context.TVGenres.Where(b => b.Name.Trim() == genre).Single();
}
return aShow;
}
}
Edit
Doing some more reading I added context.ObjectStateManager to my debug watchlist and I can see everytime I create a new TVShow entity a new record is added to _addedEntityStore. Actually if I remove context.TVShows.AddObject(show) the code still updates the database so manually adding to the context seems redundant.
If your are inserting object by foreach loop > better to keep the Primary Key outside and make it increment!
eg: int newID= Shows.Select(d=>d.Id).Max();
foreach(............)
{
show.Id = newID++;
.
.
. //remaining fields
.
context.TVShows.AddObject(show);
}
context.SaveChanges();
it works for me...!!
Turns out context.TVShows.AddObject(show) is unnecessary in my case, I was inadvertently adding all created show entities to the context when this query runs
aShow.TVGenre = context.TVGenres.Where(b => b.Name.Trim() == genre).Single();
This is not what I wanted, I just wanted to create the object, then decide whether to add it. Will be pretty easy to fix now I know why it's happening.
I am currently trying to create a new order (which will be shown below) in a web service, and then send that data to insert a new row into the database. For some reason my DBML / Data Context does not allow me to use InsertOnSubmit.
Any ideas? I haven't used Linq to Sql in about 7 months.
Thanks in advance.
[WebMethod]
public string InsertOrderToDatabases()
{
//Start Data Contexts ------
DataContext db = new DataContext(System.Configuration.ConfigurationManager.AppSettings["RainbowCMSConnectionString"]);
DataContext dcSqlOES = new DataContext(System.Configuration.ConfigurationManager.AppSettings["OESConnectionString"]);
//Get table from local database
Table<Schedule> Schedule = db.GetTable<Schedule>();
//Find last order number in databases
var lastOrderNumber = from lOrder in Schedule
orderby lOrder.templ_idn descending
select lOrder.templ_idn;
int firstOrderID;
var firstOrder = lastOrderNumber.FirstOrDefault();
firstOrderID = firstOrder.Value + 1;
qrOrder qrOrd = new qrOrder
{
.... data in here creating a new order
};
//TODO: fix below with an insert on submit
if (qrOrd != null)
{
// **Schedule.InsertOnSubmit(qrOrd);**
}
//db.GetTable<Schedule>().InsertOnSubmit(qrOrd);
try
{
//Submit the changes to the database
db.SubmitChanges();
return "Orders were sent to the databases.";
}
catch ()
{
}
}
Based on your response, it appears that you are using the wrong table, or perhaps the wrong data type. I also noticed that when you declare your localSchedule variable, you declare it as type Table<Schedule>, which means it should contain Schedule entities, not qrOrder entities.
Table<TEntity>.InsertOnSubmit expects a specific strongly typed entity to be passed in. In your case, it is expecting Web_Service.Schedul‌e, but you are trying to pass in a qrOrder.
Schedule.InsertOnSubmit(qrOrd);
That line will not treat to submit changes to connected entity , Try this
db.Schedule.InsertOnSubmit(qrOrd);
db.SubmitChanges();
you can try with
db.GetTable(typeof(Schedule)).InsertOnSubmit(qrOrd);
Or
db.GetTable(qrOrd.GetType()).InsertOnSubmit(qrOrd);
I'm new to Entify Framework so this is probably a very basic question. In a WinForms application I have a data entry page that works fine until I add a listbox and try to update the database with the selections that have been made.
On the form the user selects a file to upload and specifies one or more departments that can access the file. Here's how I thought it would work:
using (var ctx = new FCEntities())
{
var batch = new Batch() { Description = txtDescription.Text, Filename = filename, Departments = (System.Data.Objects.DataClasses.EntityCollection<Department>)lstDepartments.SelectedItems };
ctx.AddToBatches(batch);
ctx.SaveChanges();
}
But when this didn't work I did some research and learned that I can't cast the SelectedItems to EntityCollection so I decided to copy the items from the original collection into a new collection and then use the new collection as follows:
using (var ctx = new FCEntities())
{
var departments = new System.Data.Objects.DataClasses.EntityCollection<Department>();
foreach (var department in lstDepartments.SelectedItems)
{
departments.Add((Department)department);
}
var batch = new Batch() {Description = txtDescription.Text, Filename = filename, Departments=departments };
ctx.AddToBatches(batch);
ctx.SaveChanges();
}
This didn't work either and gave this error on the departments.Add line:
"An object that is attached to an ObjectContext cannot be added to an
EntityCollection or EntityReference that is not associated with a
source object."
I don't understand because it doesn't appear to me that the department object is attached to the ObjectContext? I'm obviously missing something fundamental, so any advice and/or links to examples of how others do this would be appreciated.
I wanted to leave an answer to this in case someone else runs into this someday. The comments left by Wiktor were helpful in getting me in the right direction. I decided I had a lack of fundamental understanding so I did some reading on MSDN and was able to resolve my issue.
The datamodel behind this existed of three tables: Batches, Departments, and Batches_Departments which allowed for a many to many relationship between Batches and Departments.
The problem with my original code/logic, in a nutshell, was that the Department objects in the ListBox were associated with a different context than the one I was using in my Save method. EF didn't like this for obvious reasons (at least now they are obvious), so in the save method I used the ID from the selected Departments to get a reference to the same Department in the current context. I could then add this Department to the newly created batch.
Here's what the code now looks like:
using (var ctx = new FCEntities())
{
var batch = new Batch() { Description = txtDescription.Text, Filename = filename};
foreach (var department in lstDepartments.CheckedItems)
{
var dept = (from d in ctx.Departments where d.DepartmentID == ((Department)department).DepartmentID select d).First();
batch.Departments.Add(dept);
}
ctx.Batches.AddObject(batch);
ctx.SaveChanges();
}
Hopefully this helps someone else who is dealing with the same issue.