Linq->Entities and foreign key table issue - c#

C# and general programming noobie here.
I have two tables. Property and Memo. There can be many Memo's to a single Property. I have, at least I think I do, the format of the object creation done correctly. The issue I do have is the Memo object doesn't save with the Property object. The Property object seems to save just fine.
Since I am a stack-noobie, I cannot post images strait into the post, so I've uploaded a couple which show both my Entities Diagram and the Referential Constraint dialogue.
www.jmtland.com/Pics/Diagram.png
www.jmtland.com/Pics/Referential%20Constraint.png
MTDBEntities1 dc = new MTDBEntities1();
Property newProp = new Property();
newProp.Address = t_Address.Text.Trim();
newProp.City = t_City.Text.Trim();
newProp.State = t_State.Text.Trim();
newProp.Zip = t_Zip.Text.ToString();
newProp.PropertyType = cb_PropertyType.Text.Trim();
if (t_SizeMin.Text.Trim().Length != 0) { newProp.SizeMin = Convert.ToInt64(t_SizeMin.Text); } // SizeMin is not required, so it won't be passed to the DB if there is no value.
newProp.SizeMax = Convert.ToInt64(t_SizeMax.Text);
newProp.SizeMetric = cb_SizeType.Text.Trim();
if (t_PriceMin.Text.Trim().Length != 0) { newProp.PriceMin = Convert.ToDecimal(t_PriceMin.Text); } // PriceMin is not required, so it won't be passed to the DB if there is no value.
newProp.PriceMax = Convert.ToDecimal(t_PriceMax.Text);
newProp.LeaseType = cb_LeaseType.Text.Trim();
newProp.WebLink = t_WebLink.Text.Trim();
newProp.Deleted = false;
newProp.DateDeleted = null;
newProp.DateCreated = DateTime.Now;
Memo newMemo = new Memo();
newMemo.Memo1 = t_PropertyMemo.Text.Trim();
newMemo.MemoDateCreated = DateTime.Now;
newProp.Memos.Add(newMemo);
dc.AddToProperties(newProp);
dc.SaveChanges();
I've been searching around for a fix for this problem for the last two days on multiple forums. I've followed so many examples that I almost forgot my original code.
Sorry for the noobness.
Update:
I have tried saving the Property Table first, then the Memo table.
-Doesn't work either.
I have run through the debugger and there seems to be data associated with the Memo object as well as the Property object contains the Memo object in question but it, for some reason, doesn't save at the same time.
I've though about a different way around it, where I could save the property, then do a new query to get the PropertID of that new object, then force save the Memo object with the PropertyID returned.
The issue I have with that method is that would mean my understanding of the Entity framework wouldn't be correct. I'd probably be able to hack my way around it but if I can't get it to work properly from the beginning, I fear that my later implementation of the same tech will be hindered by my inability to get it right from the get go. I've dabbled in programming before and the one thing I've learned is if you don't learn the basics right the first time, the rest of your experience can be corrupted.

The comment from RPM1984 seems to have worked. I don't know why that worked over what I tried but whatever, I can now move onto my next 4 hour block of programming a single method!
Do you have a navigational property
called "Memos" on the "Property"
entity on your EDMX? I think the last
line should be
dc.Properties.AddObject(newProp) –
RPM1984 5 hours ago

Related

DbContext not saving changes it shows it has

The goal is simple. I need to update the LastUpdated column in the Schedule table. I've tried several different methods to achieve that goal but with no success. I'm certain the code is pointing to the correct database and I'm also checking the correct [local] database for the changes. When a break point is set on SaveChanges(), the code halts at that point. I can see that "db" contains the updated Date/Time information for the correct record. Yet, it does not save it to the database.
Having gone through Stack Overflow, I've tried some suggestions like using Attach and setting the Entity State [to Modified]. Neither of those suggestions worked. HasChanges returns false, even though I can see the change is applied to the context variable.
Also, the class this method is in contains other methods that have no problem accessing the database and doing some inserts. The below code is just three different attempts to give you an idea on how I'm trying to do it. Any suggestions would be greatly appreciated.
public static void UpdateLastUpdated(int scheduleId)
{
using (var db = new MyContext())
{
var schedule = from s in db.Schedule where s.Id == scheduleId select s;
schedule.FirstOrDefault().LastUpdated = DateTime.Now;
db.SaveChanges();
var schedule2 = db.Schedule.Find(scheduleId);
schedule2.LastUpdated = DateTime.Now;;
db.SaveChanges();
var schedule3 = db.Schedule.Single(s => s.Id == scheduleId);
schedule3.LastUpdated = DateTime.Now;
db.SaveChanges();
}
}
You must indicate the change
db.Entry(schedule3).State = EntityState.Modified;
or
db.Entry(schedule3).Property(x => x.LastUpdated).IsModified = true;
So as it turns out, after a lot of trial and error... The issue was because the column was computed. I tried updating another column in the same table from that method and it worked fine. Then I did some research on computed columns and found that to be the problem. After removing the annotation, the code works fine. Now I just need to figure out how to get the default value set without the annotation.
Thank you to everyone who offered solutions and comments. Much appreciated!

Salesforce: create Opportunity Line Items along with Opportunity from C#

using Salesforce's enterprise wsdl I am trying to save opportunity line items along with opportunity. But I am getting following error:
INVALID_FIELD: No such column 'OpportunityLineItems' on entity 'Opportunity' If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.
Here is my code to create line items:
if (oppLineItems.Count > 0)
{
sfOpportunity.OpportunityLineItems = new QueryResult();
sfOpportunity.HasOpportunityLineItem = true;
sfOpportunity.OpportunityLineItems.records = oppLineItems.Values.ToArray();
Pricebook2 priceBook = new Pricebook2();
priceBook.PricebookEntries = new QueryResult();
priceBook.PricebookEntries.records = new List<PricebookEntry>() { priceBookEntry }.ToArray();
sfOpportunity.Pricebook2 = priceBook;
}
oppLineItems is a dictionary whole values have proxy objects of opportunity line items.
sfOpportunity is proxy object of Opportunity which is then sent to Salesforce.
There's a very similar question here, not sure if we should mark it as duplicate though: Salesforce: Creating OpportunityLineItems as part of the Opportunity in PHP
OpportunityLineItems on Opportunity isn't a real field. Its something called "relationship name"... Similar to table alias in normal databases, useful especially when you're making joins. And HasOpportunityLineItem is a readonly field :) And I don't think these should be QueryResult, check http://www.salesforce.com/us/developer/docs/api/Content/sample_create_call.htm for some hints?
You will need to insert the Opportunity first, the operation result will give you the record's Id. Then you should insert a list (array) of the line items.
This means 2 API calls and extra considerations what to do when the Opp header saves OK but one or more lines fails... So maybe it's good idea to write an Apex webservice like I suggested in that other question.

RavenDB namespace change on document object throws "Unable to cast object" Error

So I am just trying to get RavenDB up and running and I have struggled with several issues but finally got it working. I was able to successfully insert and pull records for display.
However, I decided to move the class I was using to generate documents from to another spot which cause a namespace change. I ran ran everything and I can still insert documents to Raven. But when I try to pull them for display purposes I get the following error:
Unable to cast object of type 'Library.Logging.RewardProviderLog' to type 'Admin.ViewModels.ImportMonitorViewModel'.
So after going through all of the other posts I could find online it seems that the issue has something to do with the Raven-Clr-Type that essentially tracks the namespace information of the object you are saving as a document.
Ok. So I went in and deleted all the documents I created since I am still just testing and trying to get things running. I even went ahead and blew away the index and recreated it. I ran my process of inserting a new log. But I still get the same error message when I try to pull them and display them.
Note: ViewModels.ImportMonitorViewModel and Library.Logging.RewardProviderLog are identical. They contain the exact same properties.
Update
Index (named ImportMonitorLogs):
from doc in docs.RewardProviderLogs
select new {doc.status, doc.newItemsCount, doc.additionalInfo, doc.lastRun};
Query:
DocumentStore RavenDBStore = new Raven.Client.Document.DocumentStore { Url = "myurl" };
RavenDBStore.DefaultDatabase = "yei-logs";
RavenDBStore.Initialize();Raven.Client.Indexes.IndexCreation.CreateIndexes(System.Reflection.Assembly.GetCallingAssembly(), RavenDBStore);
using(var session = RavenDBStore.OpenSession())
{
model = (from log in session.Query<ViewModels.ImportMonitorViewModel>("ImportMonitorLogs")
orderby log.lastRun descending
select log).ToList();
}
Putting aside the rename and what might have worked before, the error matches the query you are attempting. You are indexing documents of type RewardProviderLog, and retrieving them directly as type ImportMonitorViewModel.
You say all of the properties are the same in both classes, but that alone won't get RavenDB to duck-type them for you. You have to be a little more explicit. This will probably work:
model = (from log in session.Query<RewardProviderLog>("ImportMonitorLogs")
orderby log.lastRun descending
select log).As<ViewModels.ImportMonitorViewModel>().ToList();
Or if you want slightly cleaner syntax (IMHO), this is equivalent:
model = session.Query<RewardProviderLog>("ImportMonitorLogs")
.OrderByDescending(x=> x.lastRun)
.As<ViewModels.ImportMonitorViewModel>()
.ToList();
The key here is that you are querying based on the type that matches the entity your index is returning, and that you use the As method to duck-type it into your view model. (This is the same thing as OfType<T>, and you can read more in the docs here).
If you want to get a bit fancier and project different fields or project from the index directly, you can look at AsProjection in the docs here.
If you're still scratching your head as to why this worked before, I can see that it might have worked if your viewmodel an entity were named the same thing - even if they were from different namespaces. They would still have the same Raven-Entity-Name metadata value.

How to Insert a copy of a row (with a new identity) using LINQ to SQL?

I have a number of tables that together make up a "Test" that somebody can take. There are multiple types (scripts) of Test a person can take. I'm working on an Edit function that will allow somebody to edit the Test Questions. I want these edited questions to show up on all new Tests of that type, but still show the old questions when viewing past test scores.
To do this each "Test" has a TestId auto-increment identity (along with its name). When a test is edited I want to make a copy of the test with a new TestId and present the questions for editing.
So what is the best way to make the copy and insert it into my table using LINQ to SQL? This:
DataContext db = new DataContext(ConnectionString);
//Copy old test into identical new test but with a different script ID
var oldScript = db.TestScripts.Single(ds => ds.TestScriptId == oldScriptID);
var newScript = oldScript;
db.TestScripts.InsertOnSubmit(newScript);
db.SubmitChanges();
of course tells me that I Cannot add an entity that already exists.
Is the only way to do this to go through every column in the TestScript and copy it manually, then insert it, and the database will give it a new Id?
Edit
I've also tried
DataContext db = new DataContext(ConnectionString);
//Copy old test into identical new test but with a different script ID
var oldScript = db.TestScripts.Single(ds => ds.TestScriptId == oldScriptID);
var newScript = new TestScript();
db.TestScripts.InsertOnSubmit(newScript);
db.SubmitChanges();
hoping that it would make a new empty row, then I could newScript = oldScript and submit the changes, but it gives me SqlDateTime overflow errors.
Is the cloning part overhere what you are looking for?
http://damieng.com/blog/2009/04/12/linq-to-sql-tips-and-tricks-2
Warning: Ugly hacky untested possibility
How about setting the id to null?
newScript.TestScriptId = null
db.TestScripts.InsertOnSubmit(newScript);
Well I see two ways for you:
Just make a "make copy" function that copies all the attributes over
Use reflection to automaticly copy all properties with the [column] attribute over (Thats a little bit hardcore, and can be alittle magical, if you get it to work)
There are some "magic" functions floating around the web, that saids that they can do it, but I would prefer number 1, and have full control myself.
Also: Ask yourself it it's really the right DB schema you are using, the you need to copy an entire tree, if a person makes a change - maybe a DB change, can make this way easier for you?

subsonic 3 and active record replacing single quotes in data

hi i am using subsonic 3 and activerecord it is my first time with this and i was just wondering if anyone can point me to some reading material with regards to inserting records.
the examples i can find for adding and editing only seem to add and update the data, but i want to check the data first and replace any single quotes with doubles etc etc
or even encode the data first, before it is added or updated, so if anyone can point me in the right direction of some real examples that would be much appreciated
thanks
dave
the column are represented as normal properties in active record objects.
the values for columns are passed using these properties. if you want to do any modifications before before pushing values to database you only need to modify these properties and then call save method on the object. like:
var arObj=new MyOrder();
arObj.OrderId = 15;
arObj.OrderDate = DateTime.Now;
arObj.Description = "..................";
suppose you want to modify Description property of MyOrder object before saving to database:
arObj.Description = Abracadabra(arObj.Description);
arObj.Save();

Categories