I'm trying to add an object to a database-first ORM EntitySet in an MVC project. I use a piece of code something like this:
public static Boolean CreateListing(string title, string description)
{
ListingEntities ce = new ListingEntities();
ce.Ads.AddObject(new Ad()
{
ID = Guid.NewGuid(),
Title = title,
Description = description,
});
return ce.SaveChanges() == 1;
}
However, the SaveChanges method throws a Data.UpdateException which is thrown by a SqlClient.SqlException. The latter says
"Cannot insert the value NULL into column 'ID', table 'Listings.dbo.Ads'; column does not allow nulls. INSERT fails.
The statement has been terminated."
I wholeheartedly agree. I just don't see why the ID should be null when it seems I set it immediately prior. Any suggestions?
Thanks,
Nathan
Someone else on my team configured the database to create its own ID's, and the issue is resolved.
Related
So am using AspNetCore 1.0 with EFCore 1.0, both latest releases as far as I am aware.
Executing a query to delete an object using the FromSql method on a DbSet throws an exception. Both the code and exception are below.
public void DeleteColumn(int p_ColumnID)
{
int temp = p_ColumnID;
string query = "DELETE FROM Columns WHERE ID = {0}";
var columnsList = m_context.Columns.FromSql(query, p_ColumnID).ToList();
foreach (Columns c in columnsList)
{
m_context.Columns.Remove(c);
}
m_context.SaveChanges();
}
After executing the FromSql call, I get the following exception
An exception of type 'System.NotSupportedException' occurred in Remotion.Linq.dll but was not handled in user code
Additional information: Could not parse expression 'value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[ASPNET5_Scrum_Tool.Models.Columns]).FromSql("DELETE FROM Columns WHERE ID = {0}", __p_0)': This overload of the method 'Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.FromSql' is currently not supported.
I have no clue how to fix this error and from Googling I have come across no similar problems.
I am also wondering, if the query/code was successful it would return an 'IQueryable object. Would that solely contain the results of the query, in this case the specific Column object to delete?
FromSql is intended to allow you to compose a custom SQL SELECT statement that will return entities. Using it with a DELETE statement is not appropriate here, since your goal is to load the records you want to delete and then delete them using the default Entity Framework mechanism. A Delete statement generally does not return the records deleted (though there are ways to accomplish that). Even if they did, the records will already be deleted and so you won't want to iterate over them and do a Remove on them.
The most straightforward way to do what you want might be to use the RemoveRange method in combination with a Where query.
public void DeleteColumn(int p_ColumnID)
{
m_context.Columns.RemoveRange(m_context.Columns.Where(x => x.ID == p_ColumnID))
m_context.SaveChanges();
}
Alternately, if you want to load your entities and iterate manually through them to
public void DeleteColumn(int p_ColumnID)
{
columnList = m_context.Columns.Where(x => x.ID == p_ColumnID);
foreach (Columns c in columnsList)
{
m_context.Columns.Remove(c);
}
m_context.SaveChanges();
}
If you really want to issue the Delete statement manually, as suggested by Mike Brind, use an ExecuteSqlCommand method similar to:
public void DeleteColumn(int p_ColumnID)
{
string sqlStatement = "DELETE FROM Columns WHERE ID = {0}";
m_context.Database.ExecuteSqlCommand(sqlStatement, p_ColumnID);
}
I had the same exception in a case where I did not use delete statement. Turns out I was using the In-Memory Database. Since it is not a real database you can't use FromSQL.
I have an MVC app in which I have just updated my model, and now I'm getting this strange error message that I can't figure out. Alls I did was update the model and save it, so something has updated something.
The error is:
'int' does not contain a definition for 'ToArray' and no extension method 'ToArray' accepting a first argument of type 'int' could be found
Here is the line that's causing the error:
viewMaster.properties = _dbLazy.spPropertyByBuildingLookup(propString, null).ToArray();
And here is the spPropertyByBuildingLookup method (of course, it's based on a SP of the same name):
public virtual int spPropertyByBuildingLookup(string propertyInclude, string propertyExclude)
{
var propertyIncludeParameter = propertyInclude != null ?
new ObjectParameter("propertyInclude", propertyInclude) :
new ObjectParameter("propertyInclude", typeof(string));
var propertyExcludeParameter = propertyExclude != null ?
new ObjectParameter("propertyExclude", propertyExclude) :
new ObjectParameter("propertyExclude", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("spPropertyByBuildingLookup", propertyIncludeParameter, propertyExcludeParameter);
}
So, essentially what I ended up doing was reverting the Model back to the way it was (we use GitHub for source control). What happened was, I updated a field in the Property table from varchar to bit. I had to delete the table from the model and re add it. When I did, it defaulted the spPropertyByBuildingLookup method to return an int (it had to remove references to the Property model that was deleted). I found this out by going into the CBA.Context.cs file after it was reverted to see what had changed.
Can someone help me with my situation. I have the following code.
class Employee {
Integer empId
String firstName
String lastName
static constraints = {
empId()
firstName()
lastName()
}
static mapping = {
id generator:'assigned', name:'empId'
version false
}
}
The code allows me to save employee through 'create' but gives the following error message
"Employee not found with id null" and also in the list, all the employees are listed but clicking on any Emp Id gives the same error. Please help. This is driving me nuts.
Rocky
Thanks for your reply. Like I mentioned I am able to save the empId in the database but get that message nonetheless and see the list with assigned ids (empId). The link points to employee/show with no number at end. However employee/show/22(empId) works fine. employee/edit/22 works too but update does not work.
I am not using any assigned sequence. Just some random integer. Maybe a better example would be to use SSN instead of empId.
Thank you once again.
You are a great help buddy. Appreciate your time and patience. I am not writing any special update or save (I am too new to dig too deep). Just using grails to generate-all. However, I did find a workaround. I changed the domain class to add variable id (Long) and added empId setter method to allocate the empId value to id. That did it. Here is my code.
class Employee {
Long id
Long empId
String firstName
String lastName
static constraints = {
empId()
firstName()
lastName()
}
static mapping = {
id generator:'assigned', name:'empId', column: 'emp_id'
version false
}
public void setEmpId(Long empId){
this.empId = empId
this.id = empId
}
}
Please feel free to suggest if you have a better way of doing that.
Regards
Rocky
If you are using the "assigned" sequence, then you have to assign the objects ids yourself before saving them. Otherwise your objects will be saved with a null or 'default 0' id. If you want GORM to assign an id for you, you need to use another type of generator, like "sequence" generator. It would be like:
id name: 'customId', generator: 'sequence', params: [sequence:'some_sequence']
More info on id generators here.
With a plain connection to SQL Server, you can specify what columns to return in a simple SELECT statement.
With EF:
Dim who = context.Doctors.Find(3) ' Primary key is an integer
The above returns all data that entity has... BUT... I would only like to do what you can with SQL and get only what I need.
Doing this:
Dim who= (From d In contect.Doctors
Where d.Regeneration = 3
Select New Doctor With {.Actor = d.Actor}).Single
Gives me this error:
The entity or complex type XXXXX cannot be constructed in a LINQ to Entities query.
So... How do I return only selected data from only one entity?
Basically, I'm not sure why, but Linq can't create the complex type. It would work if you were creating a anonymous type like (sorry c# code)
var who = (from x in contect.Doctors
where x.Regeneration == 3
select new { Actor = x.Actor }).Single();
you can then go
var doctor = new Doctor() {
Actor = who.Actor
};
but it can't build it as a strongly typed or complex type like you're trying to do with
var who = (from x in contect.Doctors
where x.Regeneration == 3
select new Doctor { Actor = x.Actor }).Single();
also you may want to be careful with the use of single, if there is no doctor with the regeneration number or there are more than one it will throw a exception, singleordefault is safer but it will throw a exception if there is more than one match. First or Firstordefault are much better options First will throw a exception only if none exist and Firstordefault can handle pretty much anything
The best way to do this is by setting the wanted properties in ViewModel "or DTO if you're dealing with upper levels"
Then as your example the ViewModel will be:
public class DoctorViewModel{
public string Actor {get;set;}
// You can add as many properties as you want
}
then the query will be:
var who = (From d In contect.Doctors
Where d.Regeneration = 3
Select New DoctorViewModel {Actor = d.Actor}).Single();
Sorry i wrote the code with C# but i think the idea is clear :)
You can just simply do this:
Dim who= (From d In contect.Doctors
Where d.Regeneration = 3
Select d.Actor).Single
Try this
Dim who = contect.Doctors.SingleOrDefault(Function(d) d.Regeneration = 3).Actor
Is there any way to use DataContext to execute some explicit SQL and return the auto-increment primary key value of the inserted row without using ExecuteMethodCall? All I want to do is insert some data into a table and get back the newly created primary key but without using LINQ (I use explicit SQL in my queries, just using LINQ to model the data).
Cheers
EDIT: Basically, I want to do this:
public int CreateSomething(Something somethingToCreate)
{
string query = "MyFunkyQuery";
this.ExecuteCommand(query);
// return back the ID of the inserted value here!
}
SOLUTION
This one took a while. You have to pass a reference for the OUTPUT parameter in your sproc in your parameter list of the calling function like so:
[Parameter(Name = "InsertedContractID", DbType = "Int")] ref System.Nullable<int> insertedContractID
Then you have to do
insertedContractID = ((System.Nullable<int>)(result.GetParameterValue(16)));
once you've called it. Then you can use this outside of it:
public int? CreateContract(Contract contractToCreate)
{
System.Nullable<int> insertedContractID = null; ref insertedContractID);
return insertedContractID;
}
Take heavy note of GetParameterValue(16). It's indexed to whichever parameter it is in your parameter list (this isn't the full code, by the way).
You can use something like this:
int newID = myDataContext.ExecuteQuery<int>(
"INSERT INTO MyTable (Col1, Col2) VALUES ({0}, {1});
SELECT Convert(Int, ##IDENTITY)",
val1, val2).First();
The key is in converting ##IDENTITY in type int, like Ben sugested.
If you insist on using raw sql queries, then why not just use sprocs for your inserts? You could get the identity returned through an output parameters.
I'm not the greatest at SQL, but I broke out LinqPad and came up with this. It's a big hack in my opinion, but it works ... kinda.
DataContext.ExecuteQuery<T>() returns an IEnumerable<T> where T is a mapped linq entity. The extra select I added will only populate the YourPrimaryKey property.
public int CreateSomething(Something somethingToCreate)
{
// sub out your versions of YourLinqEntity & YourPrimaryKey
string query = "MyFunkyQuery" + "select Convert(Int, SCOPE_IDENTITY()) as [YourPrimaryKey]";
var result = this.ExecuteQuery<YourLinqEntity>(query);
return result.First().YourPrimaryKey;
}
You'll need to modify your insert statement to include a SELECT ##Identity (SQL Server) or similar at the end.