I am learning MVC2 and I am trying to create a data request management system. Somewhat like a ticketing system. A quick question, in my mvc controller class I have a post-create
[HttpPost]
public ActionResult Create(Request request)
{
if (ModelState.IsValid)
{
try
{
// TODO: Add insert logic here
var db = new DB();
db.Requests.InsertOnSubmit(request);
db.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View(request);
}
}
else
{
return View(request);
}
}
Ok, this is extremely simple enough, well I add my view and once I create a row I get the 0 first in my Primary Key row. Then it will not increment anymore, I goto add another row and the catch returns me to the same view I am on. It seems that the primary key int id is not incrementing.
How do you auto increment the id (type int) here? I am a bit confused why MVC isn't handling this since it is the primary key type int. It will only make the first row with the id = 0 and that's all.
Your ID column needs to be set as an Identity column in the table in SQL server.
Also you should create your DB data context in a using:
using(var db = new DB())
{
db.Requests.InsertOnSubmit(request);
db.SubmitChanges();
return RedirectToAction("Index");
}
Otherwise you're spilling connections all over the place; and creating more memory leaks than an early build of windows (well, depending on your traffic ;) )
Related
When I attempt to update a record from entity framework the record is being deleted from the table. There are no errors thrown so it really has me baffled what is happening.
I am fairly new to entity framework and asp.net. I've been learning it for about a month now.
I can update the record without any issues from SQL Server but not from vs. Here is the code to update the db:
// GET: /Scorecard/Edit/5
public ActionResult Edit(int id, string EmployeeName)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
CRS_Monthly crs_monthly = GetAgentById(id);
crs_monthly.EmployeeName = EmployeeName;
if (crs_monthly == null)
{
return HttpNotFound();
}
return View(crs_monthly);
}
// POST: /Scorecard/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="REC_ID,Cur_Plan,Plan_Update,Comments,Areas_Improve,Strengths,UPDATED_BY,UPDATED_TIME,Agent_Recognition")] CRS_Monthly crs_monthly)
{
if (ModelState.IsValid)
{
crs_monthly.UPDATED_TIME = DateTime.Now;
crs_monthly.UPDATED_BY = Request.LogonUserIdentity.Name.Split('\\')[1];
db.Entry(crs_monthly).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(crs_monthly);
}
When I run the debugger crs_monthly is valid and looks fine until db.SaveChanges(). Any help is greatly appreciated!
You should never save an instance of your entity created from a post, especially when you're utilizing Bind to restrict which properties are bound from the post data. Instead, always pull the entity fresh from the database and map the posted values on to it. This ensures that no data is lost.
Using Bind is a horrible practice, anyways. The chief problem with it is that all your properties are listed as string values, and you're introducing maintenance concerns. If remove one of these properties or change the name, the Bind list is not automatically updated. You must remember to change every single instance. Worse, if you add properties, you have to remember to go back and include them in this list or else your data just gets silently dropped with no notice.
If you need to only work with a subset of properties on your entity, create a view model containing just those properties. Then, again, map the posted values from your view model onto an instance of your entity pulled fresh from the database.
I'm working on a module in orchardCMS and I am trying to save object in database but when I invoke the method create it throws exception saying
"NHibernate Property Value exception"
not-null property references a null or transient value LinksHandling.Models.Links_DM.ContentItemRecord
In my db table all columns are nullable but ID column is not nullable and Id Column is Identity so in my object I have values in all attributes and id is set to 0.
When I go to save this object as below it donot work. However I have made such a function earlier and it was working as well.
public bool createLink(Links_DM linkModel)
{
var link = _linksRepository.Table.FirstOrDefault(p => p.LinkUrl == linkModel.LinkUrl);
if (link == null)
{
try {
_linksRepository.Create(linkModel);
return true;
}
catch (Exception)
{
return false;
}
}
return false;
}
I'm banging my head to figure the issue but could not reach to a solution yet.
here is my Migration.cs
SchemaBuilder.CreateTable(typeof(Links_DM).Name,
table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("LinkUrl")
.Column<string>("LinkName")
.Column<int>("PageId")
.Column<bool>("IsActive")
);
Please help me figure out The issue.
Thanks,
Sohaib
I have two different processes (on different machines) that are reading and updating a database record.
The rule I need to ensure is that the record must only be updated if the value of it, lets say is "Initial". Also, after the commit I would want to know if it actually got updated from the current process or not (in case if value was other than initial)
Now, the below code performs something like:
var record = context.Records
.Where(r => (r.id == id && r.State == "Initial"))
.FirstOrDefault();
if(record != null) {
record.State = "Second";
context.SaveChanges();
}
Now couple of questions
1) From looking at the code it appears that after the record is fetched with state "Initial", some other process could have updated it to state "Second" before this process performs SaveChanges.
In this case we are unnecessarily overwriting the state to the same value. Is this the case happening here ?
2) If case 1 is not what happens then EntityFramework may be translating the above to something like
update Record set State = "Second" where Id = someid and State = "Initial"
and performing this as a transaction. This way only one process writes the value. Is this the case with EF default TransactionScope ?
In both cases again how do I know for sure that the update was made from my process as opposed to some other process ?
If this were in-memory objects then in code it would translate to something like assuming multiple threads accessing same data structure
Record rec = FindRecordById(id);
lock (someobject)
{
if(rec.State == "Initial")
{
rec.State = "Second";
//Now, that I know I updated it I can do some processing
}
}
Thanks
In general there are 2 main concurrency patterns that can be used:
Pessimistic concurrency: You lock a row to prevent others from unexpectedly changing the data you are currently attempting to update. EF does not provide any native support for this type of concurrency pattern.
Optimistic concurrency: Citing from EF's documentation: "Optimistic concurrency involves optimistically attempting to save your entity to the database in the hope that the data there has not changed since the entity was loaded. If it turns out that the data has changed then an exception is thrown and you must resolve the conflict before attempting to save again." This pattern is supported by EF, and can be used rather simply.
Focusing on the optimistic concurrency option, which EF does support, let's compare how your example behaves with and without EF's optimistic concurrency control handling. I'll assume you are using SQL Server.
No concurrency control
Let's start with the following script in the database:
create table Record (
Id int identity not null primary key,
State varchar(50) not null
)
insert into Record (State) values ('Initial')
And here is the code with the DbContext and Record entity:
public class MyDbContext : DbContext
{
static MyDbContext()
{
Database.SetInitializer<MyDbContext>(null);
}
public MyDbContext() : base(#"Server=localhost;Database=eftest;Trusted_Connection=True;") { }
public DbSet<Record> Records { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new Record.Configuration());
}
}
public class Record
{
public int Id { get; set; }
public string State { get; set; }
public class Configuration : EntityTypeConfiguration<Record>
{
public Configuration()
{
this.HasKey(t => t.Id);
this.Property(t => t.State)
.HasMaxLength(50)
.IsRequired();
}
}
}
Now, let's test your concurrent update scenario with the following code:
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
var record = context.Records
.Where(r => r.Id == 1 && r.State == "Initial")
.Single();
// Insert sneaky update from a different context.
using (var sneakyContext = new MyDbContext())
{
var sneakyRecord = sneakyContext.Records
.Where(r => r.Id == 1 && r.State == "Initial")
.Single();
sneakyRecord.State = "Sneaky Update";
sneakyContext.SaveChanges();
}
// attempt to update row that has just been updated and committed by the sneaky context.
record.State = "Second";
context.SaveChanges();
}
}
If you trace the SQL, you will see that the update statement looks like this:
UPDATE [dbo].[Record]
SET [State] = 'Second'
WHERE ([Id] = 1)
So, in effect, it doesn't care that another transaction sneaked in an update. It just blindly writes over whatever the other update did. And so, the final value of State in the database for that row is 'Second'.
Optimistic concurrency control
Let's adjust our initial SQL script to include a concurrency control column to our table:
create table Record (
Id int identity not null primary key,
State varchar(50) not null,
Concurrency timestamp not null -- add this row versioning column
)
insert into Record (State) values ('Initial')
Let's also adjust our Record entity class (the DbContext class stays the same):
public class Record
{
public int Id { get; set; }
public string State { get; set; }
// Add this property.
public byte[] Concurrency { get; set; }
public class Configuration : EntityTypeConfiguration<Record>
{
public Configuration()
{
this.HasKey(t => t.Id);
this.Property(t => t.State)
.HasMaxLength(50)
.IsRequired();
// Add this config to tell EF that this
// property/column should be used for
// concurrency checking.
this.Property(t => t.Concurrency)
.IsRowVersion();
}
}
}
Now, if we try to re-run the same Main() method we used for the previous scenario, you will notice a change in how the update statement is generated and executed:
UPDATE [dbo].[Record]
SET [State] = 'Second'
WHERE (([Id] = 1) AND ([Concurrency] = <byte[]>))
SELECT [Concurrency]
FROM [dbo].[Record]
WHERE ##ROWCOUNT > 0 AND [Id] = 1
In particular, notice how EF automatically includes the column defined for concurrency control in the where clause of the update statement.
In this case, because there was in fact a concurrent update, EF detects it, and throws a DbUpdateConcurrencyException exception on this line:
context.SaveChanges();
And so, in this case, if you check the database, you'll see that the State value for the row in question will be 'Sneaky Update', because our 2nd update failed to pass the concurrency check.
Final thoughts
As you can see, there isn't much that needs to be done to activate automatic optimistic concurrency control in EF.
Where it gets tricky though is, how do you handle the DbUpdateConcurrencyException exception when it gets thrown? It will largely be up to you to decide what you want to do in this case. But for further guidance on the topic, you'll find more information here: EF - Optimistic Concurrency Patterns.
I am using ASP.NET MVC2 in Visual Studio 2008. I believe the SQL Server is 2005. I am using Entity Framework to access the database.
I've got the following table with a composite primary key based upon iRequest and sCode:
RequestbyCount
iRequest integer
sCode varchar(10)
iCount integer
iRequest is a foreign key to a list of requests.
When a request is updated, I want to clear out the existing RequestbyCounts for that request and then add in the new RequestbyCounts. More than likely, the only difference between the old rows will be the Count.
For my code, I attempt it as follows:
//delete ALL our old requests
var oldEquipList = (from eq in myDB.dbEquipmentRequestedbyCountSet
where eq.iRequestID == oldData.iRequestID
select eq).ToList();
foreach (var oldEquip in oldEquipList)
{
myDB.DeleteObject(oldEquip);
}
// myDB.SaveChanges(); <---- adding this line makes it work
//add in our new requests
foreach (var equip in newData.RequestList) //newData.RequestList is a List object
{
if (equip.iCount > 0)
{
//add in our actual request items
RequestbyCount reqEquip = new RequestbyCount();
reqEquip.sCodePrefix = equip.sCodePrefix;
reqEquip.UserRequest = newRequest;
reqEquip.iCount = equip.iCount;
myDB.AddToRequestbyCount(reqEquip);
}
}
myDB.SaveChanges(); //save our results
The issue is when I run it with the intermediate SaveChanges line uncommented, it works as desired. But my understanding is that doing this breaks the transaction apart.
If I leave the intermediate SaveChanges commented out as above, the process fails and I receive a
Violation of PRIMARY KEY constraint
'PK_RequestbyCount'. Cannot insert
duplicate key in object
'dbo.RequestbyCount'.\r\nThe statement
has been terminated.
Obviously, without doing the intermediate SaveChanges, the old rows are NOT removed as desired.
I do NOT want the results saved unless everything succeeds.
I would rather not take the following approach:
//add in our new requests
foreach (var equip in newData.RequestList)
{
if (equip.iCount > 0) && (**it isn't in the database**)
{
//add in our actual request items
RequestbyCount reqEquip = new RequestbyCount();
reqEquip.sCodePrefix = equip.sCodePrefix;
reqEquip.UserRequest = newRequest;
reqEquip.iCount = equip.iCount;
myDB.AddToRequestbyCount(reqEquip);
} else if (**it is in the database**) && (equip.iCount == 0) {
**remove from database**
} else {
**edit the value in the database**
}
}
Am I stuck doing the above code that basically makes a bunch of little calls to the database to check if an item exists?
Or is there some method that tell the framework to attempt to delete the rows I want but rollback if there is a failure inserting the new rows?
You don't appear to be using transactions at all. You need to wrap all your code in
using (TransactionScope transaction = new TransactionScope())
{
...
transaction.Complete();
}
Even better
using (TransactionScope transaction = new TransactionScope())
{
try
{
your code
transaction.Complete();
}
catch(Exception)
{
// handle error
}
}
Using the try/catch block will ensure that the transaction is not committed if an exception occurs, which is what you stated you wanted.
Lot's more on entity framework transactions at Microsoft's web site. The explanations there are quite good.
I've run into some trouble with unique constraints in NHibernate.
I have a User entity that is mapped with a unique constraint for the Username property. What I want to do is to be able to check if a particular username exists before a new user is added and also before an existing user updates it's username.
The first scenario (adding a new user) works just fine. However, when I try to check if the username exists before updating an existing user, I get a constraint violation. Here's what the code for my Save method looks like.
public void Save<T>(T entity) where T : User
{
using (var session = GetSession())
using (var transaction = session.BeginTransaction())
{
try
{
CheckIfUsernameExists(entity);
session.SaveOrUpdate(entity);
session.Flush();
transaction.Commit();
}
catch (HibernateException)
{
transaction.Rollback();
throw;
}
}
}
The constraint is violated in the CheckIfUsernameExists() method and it looks like this:
public void CheckIfUsernameExists<T>(T entity) where T : User
{
var user = GetUserByUsername(entity);
if (user != null)
throw new UsernameExistsException();
}
private T GetUserByUsername<T>(T entity) where T : User
{
var username = entity.Username;
var idToExclude = entity.Id;
var session = GetSession();
var user = session.CreateCriteria<T>()
.Add(Restrictions.Eq("Username", username))
.Add(Restrictions.Not(Restrictions.IdEq(idToExclude)))
.UniqueResult() as T;
return user;
}
It is the session.CreateCriteria() line that causes it to crash resulting in an NHibernateException (SQLiteException) with the message "Abort due to constraint violation. column Username is not unique".
Is it related to the NHibernate cash? The entity that is passed to the save method has been updated with the desired username at the time session.CreateCriteria() is called.
Maybe I'm doing this all wrong (I am an NHibernate beginner) so please feel free to state the obvious and suggest alternatives.
Any help is much appreciated!
Hmm, I'm not sure about the core of the problem, but for the strategy of trying to see whether a user already exists, why do you need the ".UniqueResult()"?
Couldn't you just assume to get a list of users which match that username and which do not have the same id as your current user (obviously). Pseudo-code like I'd do something like this
public bool ExistsUsername(string username, int idToExclude)
{
IList<User> usersFound = someNHibernateCriteria excluding entries that have id = idToExclude
return (usersFound.Count > 0)
}
Two thoughts:
- Why don't you just SaveOrUpdate and see if you succeed. Is that not possible in your scenario?
- I've seen you mentioning SQLite. Is that your real production system, or just something you use for testing. If so, have you checked if it's SQLite that makes the problems, and the query works against a fully featured DBMS? - SQLite frequently makes that kind of problems, because it does not support every kind of constraint...
Are you sure the exception is thrown at CreateCriteria? Because, I don't see how you could get a SQLlite constraint exception from a select statement. I do virtually the same thing...
public bool NameAlreadyExists(string name, int? exclude_id)
{
ICriteria crit = session.CreateCriteria<User>()
.SetProjection(Projections.Constant(1))
.Add(Restrictions.Eq(Projections.Property("name"), name));
if (exclude_id.HasValue)
crit.Add(Restrictions.Not(Restrictions.IdEq(exclude_id.Value)));
return crit.List().Count > 0;
}
I would look at the order of the generated sql to see what's causing it. If that entity was loaded in that session, it could be getting updated before the query.
transaction.Rollback() doesn't remove your entity from session cache, use session.Evict() instead.
See:
- https://www.hibernate.org/hib_docs/nhibernate/html/performance.html#performance-sessioncache