LinqToSql - "insert on submit" - linq-to-sql

I'm trying to insert a row in to one of my tables,
so I look over the web to find an example for using the DATACONTEXT and found this one:
protected void buttonSave_Click(object sender, EventArgs e)
{
using (NorthwindDataContext context = new NorthwindDataContext())
{
Customer customer = new Customer
{
CustomerID = textBoxCustomerID.Text,
CompanyName = textBoxCompanyName.Text,
ContactName = textBoxCustomerName.Text,
ContactTitle = textBoxTitle.Text,
Address = textBoxAddress.Text,
City = textBoxCity.Text,
Region = textBoxRegion.Text,
PostalCode = textBoxPostalCode.Text,
Country = textBoxCountry.Text,
Phone = textBoxPhone.Text,
Fax = textBoxFax.Text
};
context.Customers.InsertOnSubmit(customer);
context.SubmitChanges();
}
}
but when I try to use it and write : context.Guides. - now I can't see the InsertOnSubmit method..
does some one know why?
thanks,
yoni.

If you are using a LINQ-to-SQL Classes model (*.dbml), the Guides table must appear in the designer. Otherwise, the Guides class must descend from System.Data.Linq.Mapping.MetaTable.

Guides must be an object that doesn't implement the InsertOnSubmit method.

Related

relational data in asp.net mvc

I am getting 500 internal server error when method called for relational table data(Employee and department 0/1 to many ) to return as jsonresult.here is the method that gets error,
public JsonResult Index()
{
var employee = db.Employees.Include(x=>x.Department).ToList();
return Json(employee, JsonRequestBehavior.AllowGet);
}
but if i convert it as follows it works fine.
public JsonResult Index()
{ var emplist = db.Employees.ToList();
EmployeeViewModel emp = new EmployeeViewModel();
List<EmployeeViewModel> employee = emplist.Select(x => new EmployeeViewModel
{ EmployeeId = x.EmployeeId,
EmployeeName = x.EmployeeName,
DepartmentId = x.DepartmentId,
DepartmentName = x.Department.DepartmentName }).ToList();
return Json(employee, JsonRequestBehavior.AllowGet);
}
Is there any way I can get first method working..?
The error you are probably getting is due to MVC attempting to serialize your entity to pass to the client and the DB Context has fallen out of scope. (It is unclear how the DbContext is scoped with the code you have provided.) Serialization will iterate through every property in the entity, and for lazy-loaded references it will attempt to load them one by one. Even if the DbContext is scoped to the request and available this is very inefficient.
To avoid issues like this, simply do not pass EF entities between server and client. Nothing good will come of it. Pass a view model that represents just the data your view needs.
When you do:
var emplist = db.Employees.ToList();
// ^ Hits the database and loads ALL employees with all fields. (Does not load referenced data associated to employees, such as the departments.)
Employee emp = new Employee();
// ^ Does absolutely nothing for your cause.
List<Employee> employee = emplist.Select(x => new Employee
{ EmployeeId = x.EmployeeId,
EmployeeName = x.EmployeeName,
DepartmentId = x.DepartmentId,
DepartmentName = x.Department.DepartmentName }).ToList();
// ^ Selects 3 fields from each employee, then lazy-loads the department (works because the dbContext is in scope) and selects 1 field from the department. By using "new Employee" you are creating a POCO of the employee, not an EF proxy so the serializer will *not* attempt to resolve any dependencies.
return Json(employee, JsonRequestBehavior.AllowGet);
// ^ Serializes the POCO Employee object.
Instead, a better solution would be to declare an EmployeeViewModel that has EmployeeId, EmployeeName, DepartmentId, and DepartmentName, then use the following.
var employeeViewModels = db.Employees
.Select(x => new EmployeeViewModel
{
EmployeeId = x.EmployeeId,
EmployeeName = x.EmployeeName,
DepartmentId = x.Department.DepartmentId,
DepartmentName = x.Department.DepartmentName
}).ToList();
return Json(employeeViewModels, JsonRequestBehavior.AllowGet);
This will populate your view models with 1 hit to the database returning just the 4 fields you want to pass to the view rather than loading every field in the Employee plus an extra DB call to load the department. The view model is just a POCO so no weird behaviour around serialization. You can populate an Employee entity, however I'd recommend avoiding doing that because it can be confusing when working with an entity that may be an EF proxy (tripping up lazy loads) vs. a POCO entity which will be missing information and the EF context knows nothing about.

linq to sql insert failed due to FK constraint, how can I submit all related objects at the same time?

I am using linq to sql and trying to insert new objects. Here's an example of my code:
public class Farm(){
public List<FarmAnimals> FarmAnimals ();
public string FarmName;
}
Public class FarmAnimal(){
public string name;
}
public void Insert(FarmModel farm)
{
using (var context = new FarmDataClassesDataContext())
{
context.Farms.InsertOnSubmit(new Farm { FarmName = farm.FarmName });
foreach (var animal in farm.FarmAnimals)
{
context.Responses.InsertOnSubmit(new FarmAnimal {name = animal.name, farmID = farm.Id });
}
context.SubmitChanges();
}
}
I get a FK constraint error when it tries to insert a farm animal, referencing the farmID (which equals 0). Since the farm hasn't been inserted yet, it doesn't have an ID for the farmanimals to refer to. How do I get the farm submitted so that the farm animals FK can be properly set?
Thanks,
The problem is you are thinking SQL way, and not ORM way.
The SQL way assigns a foreign key:
InsertOnSubmit(new FarmAnimal {name = animal.name, farmID = farm.Id });
The ORM way assigns entities. Notice the part between ** ** in the following code sample.
var myFarm = new Farm { FarmName = farm.FarmName };
Con...InsertOnSubmit(myFarm)
Con...InsertOnSubmit(new FarmAnimal {name = animal.name, **farm = myFarm**});
Because you assign the entity, proper insertions will be handled and as a bonus in one transaction.
You have to submitChanges before inserting the FarmAnimals, and you need to have the column auto creating the key with autoincrement. Also make sure that the column in the table object in the DBML-file auto updated on insert.
public class Farm(){
public List<FarmAnimals> FarmAnimals ();
public string FarmName;
}
Public class FarmAnimal(){
public string name;
}
public void Insert(FarmModel farm)
{
using (var context = new FarmDataClassesDataContext())
{
Farm newFarm = new Farm { FarmName = farm.FarmName }; <--- New
context.Farms.InsertOnSubmit(newFarm); <---Edited
context.SubmitChanges(); <--- New
foreach (var animal in farm.FarmAnimals)
{
context.Responses.InsertOnSubmit(new FarmAnimal {name = animal.name, farmID = newFarm.Id }); <--- Edited
}
context.SubmitChanges();
}
}
To expand on Pleun's answer: You need to assign entities rather than IDs. The property that you're trying to assign to is mapped to a column with a foreign-key constraint, so it won't work for assigning an entity--to do that you instead need a property that maps to the relationship between two tables. How you do that varies by the tool you're using.
For the purposes of this explanation, I'll assume that you have a Farm table with a primary-key column called ID and another column called Name; and a FarmAnimal table with a foreign-key column named FarmFK that points to the Farm table and another column called Name.
Based on the DataContext part of the name I assume you're using the O/R Designer tool built in to Visual Studio, right? If so, go to the O/R Designer by opening your dbml file, select the association (represented as an arrow) between Farm and FarmAnimal (if there's not already an arrow, select the Association tool from the Toolbox and drag from Farm to FarmAnimal), and view the association's properties. You'll see properties called "Child Property" and "Parent Property". (The parent table is the table with the primary key in the relationship.) Expand those to see the "Name" sub-property of each. Those are the property names you'd use in code to access the two ends of the relationship. Typically they have poorly-chosen names based on the automatic generation, so rename them as needed. In this case let's rename the parent property's name to Animals and the child property's name to 'Farm'. You'd then be able to do the following in your code:
public void Insert(FarmModel farmModel)
{
using (var context = new FarmDataClassesDataContext())
{
var farm = new Farm
{
Name = farmModel.FarmName
};
context.Farms.InsertOnSubmit(farm);
foreach (var animalModel in farmModel.FarmAnimals)
{
var critter = new FarmAnimal
{
Name = animalModel.name,
Farm = farm
}
context.Responses.InsertOnSubmit(critter);
}
context.SubmitChanges();
}
}
Does that answer your need?

Using Find in CodeFirst (EntityFramework) to get non-primary keys

My understanding is that find only takes the primary key as the parameter. That works great if the value you are looking for is actually the primary key. In my case, I have a class like this:
public class Chamber
{
[Key]
public int Id {get;set;}
public string ChamberName { get; set; }
}
I want to check whether a given ChamberName exists in either my context or the database itself. How can I do that? Do I have to somehow enumerate of the context myself first, then, look it up in the database with a call like db.Chambers.where(a=>a.ChamberName.equals...?
I can see it working well if ChamberName is my primary key, but it is not.
THanks,
There is a property called Local in the DbSet. You can query that first to find entities loaded to the context.
var entity = db.Chambers.Local.Where(/**/).SingleOrDefault();
if (entity == null)
{
entity = db.Chambers.Where(/**/).SingleOrDefault();
}
You can't use the .Find() method - but how about:
public Chamber FindByChamberName(string chamberName)
{
using(MyDbContext ctx = new MyDbContext())
{
Chamber result = ctx.Chambers
.FirstOrDefault(c => string.Compare(c.ChamberName, chamberName, true));
return result;
}
}
You don't have to manually enumerate anything - just retrieve the first occurence of a chamber by that name - or none.
If you just need to know whether a given chamber (specified by its ChamberName) exists or not, you could use the .Any() method in Linq:
using(MyDbContext ctx = new MyDbContext())
{
return ctx.Chambers.Any(c => string.Compare(c.ChamberName, chamberName, true));
}

Can I update 1 object only with Linq to SQL?

Its a simple question, but I'm not aware of the answer and I couldn't get it to work.
Can I update only one entity on the entire DataContext? Or should I follow plain ADO.NET for this operation only?
Edit:
public MyObject GetMyObjectById(int selectedId)
{
DataContext db = _dbManager.GetContext();
return db.MyObject.SingleOrDefault(p => p.Id == selectedId);
}
I am getting an object with the above query...
I am querying then for an integer...on another table/object
public int GetMyInteger()
{
DataContext db = _dbManager.GetContext();
return db.MyAnotherObject.FirstOrDefault().MyInteger;
}
Everything is fine for all my operations...but now i just want to update only the integer i got from the database...
public void SetMyInteger(int updInteger)
{
DataContext db = new DataContext(ConnectionString);
MyAnotherObject theEntity = db.MyAnotherObject.FirstOrDefault();
atheEntity.MyInteger = updInteger;
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
The above method deleted MyObject i got from the first query!!! Of course if i use the static context DataContext tries to update MyObject and MyAnotherObject which seems the correct behaviour.
Edit:
I have changed the method getting the integer with a new datacontext as well and seems to working correctly, i have a strange thought on why called the delete method, because it was the method that was called, but again .. is working now...
Thank you all for your time.
Yes it's possible. What have you tried? It should be as simple as this:
using (var dc = new YourDataContext())
{
Person p = dc.Persons.Take(1).Single();
p.FirstName = "Ahmad";
dc.SubmitChanges();
}
Yes, you can:
Foo foo = dc.Foos.Where(foo => foo.Id == 345).Single();
foo.Name = "foo";
dc.SubmitChanges();

What's the best way to save a one-to-many relationship in Linq2Sql?

I'm trying to figure out the best way to save a simple one-to-many relationship in Linq2Sql.
Lets assume we have the following POCO model (pseduo code btw):
Person has zero to many Vechicles.
class Person
{
IList<Vehicle> Vehicle;
}
class Vehicle
{
string Name;
string Colour;
}
Now, when i save a Person, i pass that poco object to the repository code (which happens to be L2S). I can save the person object fine. I usually do this.
using (Db db = new Db())
{
var newPerson = db.People.SingleOrDefault(p => p.Id == person.Id) ?? new SqlContext.Person();
// Left to right stuff.
newPerson.Name = person.Name;
newPerson.Age = person.Age;
if (newPerson.Id <= 0)
db.People.InsertOnSubmit(newPerson);
db.SubmitChanges();
}
i'm not sure where and how i should handle the list of vehicles the person might have? any suggestions?
using (Db db = new Db())
{
var newPerson = db.People.SingleOrDefault(p => p.Id == person.Id) ?? new SqlContext.Person();
// Left to right stuff.
newPerson.Name = person.Name;
newPerson.Age = person.Age;
// add vehicles.
Vehicle firstV = new Vehicle();
firstV.Name = "some name";
firstV.Person = newPerson; // need to do this to set the person Id on the vehicle.
newPerson.Vehicle.Add(firstV);
// now when you save the Person it should save the Vehicle list
// if you set Cascade save update on the list. (not sure how to do that in L2S
if (newPerson.Id <= 0)
db.People.InsertOnSubmit(newPerson);
db.SubmitChanges();
}
Now you may choose to construct the list of vehicles at another level , with the data that's coming from the interface.
But you need to remember that it's not enough to add the Vehicle to the list on the Person object , you also need to set the vehicles Person property to the person that has the vehicles.
Observation I'm not sure about this but when you do db.People.SingleOrDefault you might be loading the whole People table in memory . That's not something you want to do. Corrected by Slace in the comments.
All you need to do is ensure that there are the appropriate relationships set up within the database.
If your Vehicle table has a PersonId and there is a foreign key between them when you add them to the DBML Linq to SQL will detect that there is a relationship between them and create a Table<T> representation of the relationship.