as the question implies I want to store images into the filesystem and save a link to it in the database.
but NHibernate doesn't save the file path in the database. here is the code:
[HttpPost]
public ActionResult Edit(Item item, HttpPostedFileBase image)
{
if (ModelState.IsValid)
{
if (image != null)
{
string imageName = image.FileName;
string location = Path.Combine(Server.MapPath("~/Content/Images/ItemImages/") , imageName);
image.SaveAs(location);
item.Image= imageName;
}
menuItemRepository.SaveOrUpdate(item);
// here the debug show the image path has correctly assigned to the image property
Debug.WriteLine(item.Image);
TempData["message"] = string.Format("{0} has been saved", item.Name);
return RedirectToAction("Index", item.Parent);
}
else
{
// there is something wrong with the data values
return View(Item);
}
}
but after repositor save or update the item, when I look at the database, the image is null. I tried to assign something ele like image name and it did work but the for image path is not working!! I'm confused why this happen. does anyone have any idea?
public class Item
{
public virtual string Image { get; set; }
}
public calss ItemMap : ClassMap<Item>
{
public ItemMap()
{
Map(x => x.Image).Length(100);
}
}
//////////Repository
public T SaveOrUpdate(T entity)
{
session.SaveOrUpdate(entity);
return entity;
}
My best guess - the save is not being flushed to the database. See the documentation:
From time to time the ISession will execute the SQL statements needed to synchronize the ADO.NET connection's state with the state of objects held in memory. This process, flush, occurs by default at the following points
from some invocations of Find() or Enumerable()
from NHibernate.ITransaction.Commit()
from ISession.Flush()
I see nothing in your code that would trigger a flush. Wrap your SaveOrUpdate in a transaction:
using (var trx = menuItemRepository.BeginTransaction())
{
menuItemRepository.SaveOrUpdate(item);
trx.Commit();
}
trx.Commit() will flush that pending update query to the database.
I had implemented a sessionPreRequest module for my MVC app. so I was doing commit() operation there.
I checked and saw my transaction is not committing and is rolling back. and checked the error and the image column in the database was nvarchar(50), but the string which had the path of image was mor than 50 characters. so I changed to nvarchar(200) and now everything works fine.
Related
I posted the question earlier, but didn't receive any correct responses, hence posting again with some edits. I have a function that accepts two parameters, IDs and Dates. When I had put breakpoints, I was able to see the Ids and the Dates selected on the page as parameter values. However, after hitting the process button, nothing happens, meaning this data isn't getting saved to the DB.
Model Classes:
public class Hello{
public string ID{ get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date{ get; set; }
}
Controller Class:
[HttpGet]
public ActionResult Selection(string ids, string dates)
{
model = new Hello();
ExtensionDB db = new ExtensionDB();
string[] IDS = ids.Split(',');
string[] DATES = dates.Split(',');
List<Hello> list = new List<Hello>();
for (int i = 0; i < IDS.Length; i++)
{
if (IDS[i] != null && IDS[i] != "")
{
Hello item = new Hello { ID = IDS[i], Date = DateTime.Parse(DATES[i]) };
list.Add(item);
}
}
if (ModelState.IsValid)
{
foreach (var row in db.Table1)
{
foreach (var row2 in db.Table2)
{
if (row.UID== row2.CID) // UID and CID are Foreign keys that join these two tables
{
foreach (var item in list)
{
if (row.UID == Convert.ToInt32(item.ID))
{
row2.ReportedDate = item.Date;
}
db.SaveChanges();
}
}
}
}
ViewBag.Message = "Success";
return View(model);
}
else
{
ViewBag.Message = "Failed";
return View(model);
}
}
I will add the view class if needed, however the problem is here.. You can also refer to it here: Saving changes to the DB MVC
Your code does not attempt to update anything. Start with confirming what the data you are passing to this POST call contains, and what you want to do with it. It looks like what you are trying to do is update the dates for a number of records. Looking at your previous post (no need to re-post another question with the same code) there are a few things..
First: Structure the data you want to pass to the POST call into a collection of simple objects containing an id and a date. For example:
{
id = rid,
date = date
}
and add those to the collection named something like "updateData" rather than two separate arrays of IDs and dates. Then in the server-side code, declare a simple view model class:
public class UpdateDateViewModel
{
public int Id { get; set; }
public DateTime Date { get; set; }
}
In the ajax call instead of:
data: { ids: ids, dates: dates },
you'll want something like:
data: { updates: updateData },
where updateData is your collection of id + date pairs.
and use that view model in your method:
public ActionResult Process(IList updates)
Provided that request data is sent as Json, ASP.Net should translate that data automatically for you, though you may need to configure ASP.Net to translate the camelCase vs PascalCase. Worst case, to test, you can use camelCase property names ("id" and "date")
Now when it comes to updating the data: Server side, please get in the habit of using meaningful variable names, not "c", "i", etc. It makes code a lot easier to understand.
public ActionResult Process(IList<UpdateDateViewModel> updates)
{
using (db = new DB())
{
//rp = new RequestProcess(); - Assuming RequestProcess is an Entity?
//var c = rp.getStuff(); - No idea what this getStuff() method does...
foreach(var update in updates)
{
var request = db.RequestProcesses.Find(update.Id);
if (request != null)
request.RequestDate = update.Date; // If we find a matching request, update it's date.
else
{ // Doesn't exist, create it and add it to the DbSet.(table)
var request = new RequestProcess { Id = update.Id, RequestDate = update.Date };
db.RequestProcesses.Add(request);
}
db.SaveChanges();
}
}
}
Now this is a very bare bones guess at what you may be trying to do. Ideally though, updates should be completely separate from adds in the sense that an update should only deal with existing records. If it comes across an ID that it cannot find it should throw an error, ignore, and/or return a status to the user that something wasn't right. Creating new entries should be a separate call and ensure that records are properly initialized with their required fields.
Your original code looked to be taking a list of IDs, but then creating a new entity and calling that "getStuff" method that didn't have the DbContext, or any of the values from the POST call, but then attempting to copy values from that entity into the string parameters that you passed (which would overwrite the Json string) None of that would have updated an entity which would never have updated your data.
Take it slow and follow the examples before attempting to adapt them to your ideas. It will be a lot more constructive and less frustrating then writing a bunch of code that doesn't really make much sense, then wondering why it doesn't work. Your original code has probably a dozen or more problems and inefficiencies. Simply pasting it up on Stack will get a lot of confusing comments based on these problems which don't really help with the first issue you want to solve. Strip it back to the minimum, start with getting the data you need to the server in a meaningful way, then from that, attempt to use that data to update your entities.
Is the essence of Project, the creation of which is necessary to check whether there is already an entity with the same name. When editing needs such as checking, but keep in mind that the old and the new name of the entity can be matched.
You also need to display an error message. For this I use interface IValidatableObject, but do not know how to tell the Validate method the object is currently being edited or created
DbContext.ValidateEntity takes the IDictionary<Object, Object> items as the second parameter. You can pass any data there and the data you pass will be passed to IValidatableObject.Validate in the ValidationContext.Items
Assuming you refer to check EF cant do for you.
This is actually difficult to check. You are checking an entity after it has been added to the context. It should not check itself and needs to consider other items in context that are not yet saved. As well as the DB. There are several 3 combinations plus an self recognition. Record a an entity record in LOCAL when ID is blank/new ie multiple new inserts needs careful coding. (Consider using temp IDs)
the not yet saved entries should be in context
Context.Set<TPoco>().Local
and get data from DB and keep in a temp list. BUT dont put in context.
Or use a SECOND context.
var matchingSet = Context.Set<TPoco>().AsNoTracking() // not into context...
.Where(t=>t.field == somevalue).ToList();
So what about logical and actual duplicates on the DB. Logical duplicates are duplicates on a field with no unique index that from a business perspective should be unique.
If you want to check those...
You need to read the DB.... BUT if these records are currently being changed, you CAN NOT just put them into the Context. You would overwrite them.
But what if the values the logical key values have changed?
Something caused a logical dup on a record on the DB may no longer be a dup once saved or vice verse. Is that still a dup or not ?
So you need to decide how you match LOCAL versus loaded records.
Ie check LOCAL and matching DB records and decidr what to do if a record is in both, only local or only db.
LOCAL ONLY and DB Only is easy.
But in both... That is your business process decision.
Problem is solved using method ModelState.AddModelError (string, string) in actions Edit and Create.
[HttpPost]
[HandleError(View="AjaxError")]
public ActionResult Edit(ProjectsViewData data)
{
if (ModelState.IsValid)
{
if (!ContainsProject(data.CurrentObject.Name))
{
db.Projects.Attach(data.CurrentObject);
db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
db.SaveChanges();
return Projects(data);
}
else
{
int projectId = (from p in db.Projects
where p.Name == data.CurrentObject.Name
select p.ProjectID).FirstOrDefault();
if (projectId == data.CurrentObject.ProjectID)
{
db.Projects.Attach(data.CurrentObject);
db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
db.SaveChanges();
return Projects(data);
}
else
{
ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
}
}
}
data.ObjectToEdit = data.CurrentObject;
return Projects(data);
}
[HttpPost]
[HandleError(View = "AjaxError")]
public ActionResult Create(ProjectsViewData data)
{
if (ModelState.IsValid)
{
if (!ContainsProject(data.CurrentObject.Name))
{
db.Projects.AddObject(data.CurrentObject);
db.SaveChanges();
return Projects(data);
}
else
{
ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
}
}
data.ObjectToAdd = data.CurrentObject;
return Projects(data);
}
Helper method:
private bool ContainsProject(string projectName)
{
if (projectName != null)
{
projectName = Regex.Replace(projectName.Trim(), "\\s+", " ");
List<string> projects = new List<string>();
var projectNames = (from p in db.Projects
select p.Name.Trim()).ToList();
foreach (string p in projectNames)
{
projects.Add(Regex.Replace(p, "\\s+", " "));
}
if (projects.Contains(projectName))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
I'm really trying hard to put everything on my project to work with the EF, but it's really getting difficult and sometimes it makes me wonder if it's really the smart move (to rely on EF against coding all the ins and outs of the database).
Well, my problem is still related to 1-N creating/editing/deleting functionality (something that should be simple, right?).
Ok, I'm pasting here some simple equivalent of my code.
For the Entities, I got the main class as:
[Table("OLIM_LOTE")]
public class Lote
{
[Key]
[Column("LOTE_ID_LOTE")]
public int? IDLote { get; set; }
[Column("LOTE_TX_OBS")]
public string Obs {get;set;}
[Column("LOTE_TX_DOCUMENTO_EXTRA")]
public string DocumentoExtra { get; set; }
[NotMapped]
public List<DocumentoLote> Documentos { get; set; }
public void LoadLists()
{
OlimpiqueDBContext myDbContext = new OlimpiqueDBContext();
var docs = (from doc in myDbContext.DocumentosLote
where doc.IDLote == this.IDLote
select doc);
this.Documentos = docs.ToList<DocumentoLote>();
}
}
[Notice that i used the nullable int? for Key - otherwise it throws me validation exception asking for a value on creation]
For the child class, i got this:
[Table("OLIM_DOCUMENTO_LOTE")]
public class DocumentoLote
{
[Key]
[Column("DOLO_ID_DOCUMENTO_LOTE")]
public int? IDDocumentoLote { get; set; }
[Column("DOCU_ID_DOCUMENTO")]
[ForeignKey("Documento")]
public int IDDocumento { get; set; }
public virtual Documento Documento { get; set; }
[Column("LOTE_ID_LOTE")]
[ForeignKey("Lote")]
public int IDLote { get; set; }
public virtual Lote Lote { get; set; }
}
[Notice that the child class has a reference back to the owner class, which are the "IDLote" and "Lote" attributes, and the owner class has a list of child class instances - so I got i bi-directional refernce - I assume that this is somehow related to the problems]
I got a Controller and View generated automatically by VS2012 with Read/Write functionality related to the class Lote.
What I did in the View can be described as: I used a Jquery DataTable to manage the child class data (the user can add "N" instances on the DataTable). I substituted the Post Button with a call to a JS method that simply gets all the data from the Form and from the DataTable and wrap it in a JSon object and send it to the controller via Ajax.
The controller method that receives it can be simplified as below:
[HttpPost]
public JsonResult Edit(Lote lote)
{
try
{
if (ModelState.IsValid) //<< HAVING PROBLEMS HERE... DETAILS BELOW
{
if (lote.IDLote.HasValue)
{
//Separete updates/inserts from deletes
List<int?> dbDocs = db.DocumentosLote
.Where(dt => dt.IDLote == lote.IDLote)
.Select(dt => dt.IDDocumentoLote)
.ToList();
List<int?> postedDocs = lote.Documentos
.Select(pt => pt.IDDocumentoLote)
.ToList();
List<int?> deletedDocs = dbDocs
.Except(postedDocs).ToList();
//Perform deletes
foreach (var delDocId in deletedDocs)
{
if (delDocId.HasValue)
{
DocumentoLote delDoc = db.DocumentosLote
.Where(dt => dt.IDLote == lote.IDLote && dt.IDDocumentoLote == delDocId)
.Single();
db.Entry(delDoc).State = EntityState.Deleted;
}
}
//Perform insert and updates
foreach (var doc in lote.Documentos)
{
if (doc.IDDocumentoLote.HasValue)
{
db.Entry(doc).State = EntityState.Modified;
}
else
{
db.Entry(doc).State = EntityState.Added;
doc.IDLote = (int)lote.IDLote;
}
}
}
else
{
db.Lotes.Add(lote);
}
db.SaveChanges();
// If Sucess== 1 then Save/Update Successfull else there it has Exception
return Json(new { Success = 1, ex = "" });
}
else
{
return Json(new { Success = 0, ex = "Falha ao tentar salvar os dados" });
}
}
catch (Exception ex)
{
// If Sucess== 0 then Unable to perform Save/Update Operation and send Exception to View as JSON
return Json(new { Success = 0, ex = ex.Message.ToString() });
}
}
Problems: Well I really passed through a lot to got to this point and now, I got only 2 problems. The first being that the creation is throwing a Validation Exception sayin that it needs an IDLote (for the child classes - but anyway, how would i have it if the owner class itself still doesn't have an Id at that point in creation?)
Second problem: Deletion dont work at all! Doesn't matter how i code it, it throws the exception "objects cannot be defined because they are attached to different ObjectContext objects". I really feel that this has something to do with the bidirectional reference between owner-children classes, but still, don't have a clue on exactly whats happening and how to solve it
I'm starting to feel really lost here. Any ideas on this would be very appreciated. Thanks
As there are a lot of views on this old question and now I do have some answer, I'm posting them for reference:
Q - Regarding the int? type for the key attributes:
A - It doesn't have to be a nullable int at all. The entity can be declared with a simple int attribute as key and when posting the JSon object from the View, back to some controller method, this attribute (the key) can be filled with the value "0". EF will generate the correct value as soon as it persists the object.
Q - Regarding the navigational attributes and how to implement the relation between the two classes when neither of them have already got a value (non-zero) on theis keys:
A - The JSon object to be sent back can implement the exact navigational relationaship between them. Wehn the controller binds the data posted to the model it should be receiving, it will "understand" their relationship and as soon as the values for the keys are generated, they will correctly reference one another.
Q - Regarding the error described on the delete method attempts:
A - When objects should interact with other objects, and those interactions should be persisted or "understood" by EF in any way, they must have been obtained, generated or attached to a same DBContext. EF rely on the DB context to create a tree of this interactions, thus, rendering impossible to build this tree when objets are not present on the same DB Context.
I want to add a relationship between multiple existing entities and another existing entity. Here is my model:
public class Term
{
public int TermId { get; set; }
public virtual ICollection<SubForm> SubForms { get; set; }
}
public class SubForm
{
public int SubFormId { get; set; }
public virtual ICollection<Term> Terms { get; set; }
}
I have an update repository method as follows:
public IQueryable<Term> GetTerms()
{
IQueryable<Term> query = db.Terms.AsNoTracking();
return query;
}
public Term UpdateTerm(Term term, IEnumerable<Expression<Func<Term, object>>> properties)
{
if (term.TermId == 0)
{
throw new InvalidOperationException("Term does not exist");
}
db.Terms.Attach(term);
if (properties != null)
{
foreach (var selector in properties)
{
string propertyName = Helpers.PropertyToString(selector.Body);
db.Entry(term).Property(propertyName).IsModified = true;
}
}
db.SaveChanges();
return term;
}
Now I assume this would work when I make this call in my service layer:
public void AddFormToTerm(int termId, int formId)
{
var term = termsRepository.GetTerms().FirstOrDefault(t => t.TermId == termId);
var subForms = termsRepository.GetSubForms().Where(t => t.FormId == formId);
//I assume this would work by adding existing forms to an existing term.
foreach (var subForm in subForms)
{
term.SubForms.Add(subForm);
}
termsRepository.UpdateTerm(term, null);
}
Unfortunately, this doesn't get updated, there is nothing in the intermediate table when I checked the database. No exception was also thrown.
Using AsNoTracking in this case is the problem. Without AsNoTracking it will work. You must keep in mind that you can update a many-to-many relationship only with the change tracking mechanism. But in your code the EF context will know about term and the SubForms collection for the first time when you call Attach in your UpdateTerm method. EF does not notice that you did add the SubForms to the term because those entities were not attached to the context (since you used AsNoTracking = "EF, please do not attach to the context!"). But after Attach nothing happened anymore before you called SaveChanges = No change = No database commands.
So removing AsNoTracking (or creating another method or a parameter to load with tracking) is the best option. Everything else will involve ugly "tricks" like this:
public Term UpdateTerm(Term term, ...)
{
//...
// Restore the state before adding the subforms = current state in DB
var tempSubForms = term.SubForms;
term.SubForms = null;
// Inform EF about this state = term exists, subforms exist
// in DB but no relationships
db.Terms.Attach(term);
foreach (var subForm in tempSubForms)
db.SubForms.Attach(subForm);
// Change the state: EF change tracking recognizes this
term.SubForms = tempSubForms;
//...
// EF now will send INSERT statements for the join table
db.SaveChanges();
return term;
}
I have a very big problem and can't seem to find anybody else on the internet that has my problem. I sure hope StackOverflow can help me...
I am writing an ASP.NET MVC application and I'm using the Repository concept with Linq To Sql as my data store. Everything is working great in regards to selecting rows from views. And trapping very basic business rule constraints. However, I'm faced with a problem in my stored procedure mappings for deletes, inserts, and updates. Let me explain:
Our DBA has put a lot of work into putting the business logic into all of our stored procedures so that I don't have to worry about it on my end. Sure, I do basic validation, but he manages data integrity and conflicting date constraints, etc... The problem that I'm faced with is that all of the stored procedures (and I mean all) have 5 additional parameters (6 for inserts) that provide information back to me. The idea is that when something breaks, I can prompt the user with the appropriate information from our database.
For example:
sp_AddCategory(
#userID INT,
#categoryName NVARCHAR(100),
#isActive BIT,
#errNumber INT OUTPUT,
#errMessage NVARCHAR(1000) OUTPUT,
#errDetailLogID INT OUTPUT,
#sqlErrNumber INT OUTPUT,
#sqlErrMessage NVARCHAR(1000) OUTPUT,
#newRowID INT OUTPUT)
From the above stored procedure, the first 3 parameters are the only parameters that are used to "Create" the Category record. The remaining parameters are simply used to tell me what happened inside the method. If a business rule is broken inside the stored procedure, he does NOT use the SQL 'RAISEERROR' keyword when business rules are broken. Instead, he provides information about the error back to me using the OUTPUT parameters. He does this for every single stored procedure in our database even the Updates and Deletes. All of the 'Get' calls are done using custom views. They have all been tested and the idea was to make my job easier since I don't have to add the business logic to trap all of the various scenarios to ensure data quality.
As I said, I'm using Linq To Sql, and I'm now faced with a problem. The problem is that my "Category" model object simply has 4 properties on it: CategoryID, CategoryName, UserId, and IsActive. When I opened up the designer to started mapping my properties for the insert, I realized that there is really no (easy) way for me to account for the additional parameters unless I add them to my Model object.
Theoretically what I would LIKE to do is this:
// note: Repository Methods
public void AddCategory(Category category)
{
_dbContext.Categories.InsertOnSubmit(category);
}
public void Save()
{
_dbContext.SubmitChanges();
}
And then from my CategoryController class I would simply do the following:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
var category = new Category();
try
{
UpdateModel(category); // simple validation here...
_repository.AddCategory(category);
_repository.Save(); // should get error here!!
return RedirectToAction("Index");
}
catch
{
// manage friendly messages here somehow... (??)
// ...
return View(category);
}
}
What is the best way to manage this using Linq to Sql? I (personally) don't feel that it makes sense to have all of these additional properties added to each model object... For example, the 'Get' should NEVER have errors and I don't want my repository methods to return one type of object for Get calls, but accept another type of object for CUD calls.
Update: My Solution! (Dec. 1, 2009)
Here is what I did to fix my problem. I got rid of my 'Save()' method on all of my repositories. Instead, I added an 'Update()' method to each repository and actually commit the data to the database on each CUD (ie. Create / Update / Delete) call.
I knew that each stored procedure had the same parameters, so I created a class to hold them:
public class MySprocArgs
{
private readonly string _methodName;
public int? Number;
public string Message;
public int? ErrorLogId;
public int? SqlErrorNumber;
public string SqlErrorMessage;
public int? NewRowId;
public MySprocArgs(string methodName)
{
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("methodName");
_methodName = methodName;
}
public string MethodName
{
get { return _methodName; }
}
}
I also created a MySprocException that accepts the MySprocArgs in it's constructor:
public class MySprocException : ApplicationException
{
private readonly MySprocArgs _args;
public MySprocException(MySprocArgs args) : base(args.Message)
{
_args = args;
}
public int? ErrorNumber
{
get { return _args.Number; }
}
public string ErrorMessage
{
get { return _args.Message; }
}
public int? ErrorLogId
{
get { return _args.ErrorLogId; }
}
public int? SqlErrorNumber
{
get { return _args.SqlErrorNumber; }
}
public string SqlErrorMessage
{
get { return _args.SqlErrorMessage; }
}
}
Now here is where it all comes together... Using the example that I started with in my initial inquiry, here is what the 'AddCategory()' method might look like:
public void AddCategory(Category category)
{
var args = new MySprocArgs("AddCategory");
var result = _dbContext.AddWidgetSproc(
category.CreatedByUserId,
category.Name,
category.IsActive,
ref args.Number, // <-- Notice use of 'args'
ref args.Message,
ref args.ErrorLogId,
ref args.SqlErrorNumber,
ref args.SqlErrorMessage,
ref args.NewRowId);
if (result == -1)
throw new MySprocException(args);
}
Now from my controller, I simply do the following:
[HandleError(ExceptionType = typeof(MySprocException), View = "SprocError")]
public class MyController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Category category)
{
if (!ModelState.IsValid)
{
// manage friendly messages
return View(category);
}
_repository.AddCategory(category);
return RedirectToAction("Index");
}
}
The trick to managing the new MySprocException is to simply trap it using the HandleError attribute and redirect the user to a page that understands the MySprocException.
I hope this helps somebody. :)
I don't believe you can add the output parameters to any of your LINQ classes because the parameters do not persist in any table in your database.
But you can handle output parameters in LINQ in the following way.
Add the stored procedure(s) you whish to call to your .dbml using the designer.
Call your stored procedure in your code
using (YourDataContext context = new YourDataContext())
{
Nullable<int> errNumber = null;
String errMessage = null;
Nullable<int> errDetailLogID = null;
Nullable<int> sqlErrNumber = null;
String sqlErrMessage = null;
Nullable<int> newRowID = null;
Nullable<int> userID = 23;
Nullable<bool> isActive=true;
context.YourAddStoredProcedure(userID, "New Category", isActive, ref errNumber, ref errMessage, ref errDetailLogID, ref sqlErrNumber, ref sqlErrMessage, ref newRowID);
}
I haven' tried it yet, but you can look at this article, where he talks about stored procedures that return output parameters.
http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx
Basically drag the stored procedure into your LINQ to SQL designer then it should do the work for you.
The dbContext.SubmitChanges(); will work only for ENTITY FRAMEWORK.I suggest Save,Update and delete will work by using a Single Stored procedure or using 3 different procedure.