Use auto generate key in asp.net - ado.net

I have a field which is an auto generated primary key. Now I need to insert a row with this field as one of its column. How should I create "insert" arguments?
protected void Button1_Click(object sender, EventArgs e)
{
new DataSet1TableAdapters.MemberTableAdapter().Insert(
1,TextBox5.Text,TextBox6.Text,
int.Parse(TextBox8.Text),
TextBox9.Text,
TextBox10.Text);
}
I got Error:
"Cannot insert explicit value for identity column in table 'Member' when
IDENTITY_INSERT is set to OFF."
Actually I shouldn't insert any value for first argument because it's auto generated. but this error appear after using this style:
protected void Button1_Click(object sender, EventArgs e)
{
new DataSet1TableAdapters.MemberTableAdapter().Insert(
TextBox5.Text, TextBox6.Text, int.Parse(TextBox8.Text),
TextBox9.Text, TextBox10.Text);
}
And I get:
Error:No overload for method insert take 5 argument
So how should I solve this problem?

Related

Entity framework migration how to seed data from previous table

I have a column of type time that I need to change to type bigint.
As I see it, the only way is to drop the column and create a new one with a bigint type.
For that I will run the following migration :
public partial class Migration1 : DbMigration
{
public override void Up()
{
DropColumn("dbo.MyDurations", "Duration");
AddColumn("dbo.MyDurations", "Duration", c => c.Long(nullable: false));
}
public override void Down()
{
DropColumn("dbo.MyDurations", "Duration");
AddColumn("dbo.MyDurations", "Duration", c => c.Time(nullable: false, precision: 7));
}
}
How can I get the data from the current column in time type and seed it to the new one by transforming it with TimeSpan.Ticks(duration) ?
From what I understood, I can only seed data from the Seed(DbContext ctx) function from the Configuration file. But the seed method is run after the migration.
Is it possible to access data before applying migration, then apply the migration and then seed the data ?
You can run your own Sql in a migration using the Sql method. You need to change your migration to something like this:
public override void Up()
{
AddColumn("dbo.MyDurations", "NewDuration", c => c.Long(nullable: false));
Sql("UPDATE dbo.MyDurations SET NewDuration = Duration");
DropColumn("dbo.MyDurations", "Duration");
RenameColumn("dbo.MyDurations", "NewDuration", "Duration");
}

EF 5.0 Code First Winforms Combobox Data Binding

I'm trying to bind some lookup tables to comboboxes on winforms. I've built the POCCO classes and generated the database. I've added the data source to my app. I drop the source tables onto the comboboxes in the designer and the binding gets set up fine for each. I've populated the tables in the db with test data.
Here's where I need help. With datasets I would simply do a tableadapter fill on the form Load event to get the data. With EF I must have to do something to load the data. Perhaps a query? Something else? I bleieve everything is set up correctly. Just need the final step to get it to load and work. Thanks.
There are many ways how to communicate with your database. I understood, you are probably using EF Code First approach. Imagine this context:
public class WinFormContext : DbContext
{
public DbSet<Car> Cars { get; set; }
}
public class Car
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
You are gonna add some record first. You create simple form with textboxs and one button.
private void button1_Click(object sender, EventArgs e)
{
using (var WinFormContext = new WinFormContext())
{
Car car = new Car { Name = textBox1.Text };
WinFormContext.Cars.Add(car);
WinFormContext.SaveChanges();
}
}
It is simple solution, how to add new record after onClick event. Now you want to show all record in Grid View. One of the possible solution is fill the controll manually:
BindingSource bindingSource = new BindingSource();
private void Form2_Load(object sender, EventArgs e)
{
var WinFormContext = new WinFormContext();
bindingSource.DataSource = WinFormContext.Cars.ToList();
dataGridView1.DataSource = bindingSource;
dataGridView1.AutoGenerateColumns = true;
}
But there is more ways how to do it. I recommend you take a look on "data binding in win forms" on Google...

Where to handle DB exceptions in Entity Framework and repository pattern

how would you design this scenario (using Entity Framework 4.1, Code First and repository pattern):
the Visual Studio solution contains the following projects
Solution
|-Web Application Project
|-DAL Project
|-Model Project
So in the Model Project there are various classes. Suppose we have in there a class called User with the following definition (stripped down):
public class User{
[Key]
public int UserId { get; set; }
....
//this property has a unique constraint created in a custom DB Initializer class
public string email { get; set; }
....
}
In the DAL Project reside the repository methods (Insert, Update etc.) and also the Initializer class:
public class MyDatabaseInitializer : IDatabaseInitializer<MyDatabase>
{
public void InitializeDatabase(MyDatabase context)
{
try
{
if (!context.Database.Exists())
{
context.Database.Create();
context.Database.ExecuteSqlCommand(
"ALTER TABLE Users ADD CONSTRAINT uc_Email UNIQUE(Email)");
}
}
catch (Exception ex)
{
throw ex.InnerException;
}
}
}
The Commit method of my Unit of Work class looks like this:
public string Commit()
{
string errorMessage = string.Empty;
try
{
Database.Commit();
}
catch (DbUpdateException updExc)
{
errorMessage = updExc.InnerException.Message;
}
return errorMessage;
}
As you see I'm handling DbUpdateException in the Commit() method of the Unit of Work class; this means for each class which could cause an update error, this would be handled here.
Suppose one inserts the User records with the following Data:
(UserId,....,Email,...)
1, ... , person1#mail.com , ...
2, ... , person1#mail.com , ...
It 's obvious that this will cause a DbUpdateException to occur. Of course this can be caught and propagated to the place where it should show up. I have the feeling that this design is completely wrong:
Validation should occur for each property separately: shouldn't this be true also for the uniqueness of values of field? Does this mean that I have to merge DAL and MODEL into one project?
How would I handle errors caused by a violation of the uniqueness for fieldA in table A, fieldB in table B, fieldC in table C? Using a generic error message "The value already exists" or "Uniqueness violation" is not very descriptive!
Should I insert another project-Business layer which takes care of such error handling?
Should I handle the errors in the (ASP.NET MVC) Action/Controller which does the update?
How to handle a proper error message in a multi language application?
I am facing the same situation and at the moment I am handling the exception in my controller.
Consider the following entity:
public class Part
{
public int Id { get; set; }
public string Number { get; set; }
}
I have a unique constraint set up on the 'Number' field in the database so if a duplicate value is entered an exception will be thrown. This is how I am handling the exception:
[HttpPost]
public ActionResult Create(Part part)
{
if (ModelState.IsValid)
{
try
{
db.Parts.Add(part);
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DbUpdateException e)
{
SqlException s = e.InnerException.InnerException as SqlException;
if (s != null && s.Number == 2627)
{
ModelState.AddModelError(string.Empty,
string.Format("Part number '{0}' already exists.", part.Number));
}
else
{
ModelState.AddModelError(string.Empty,
"An error occured - please contact your system administrator.");
}
}
}
return View(part);
}
All this does is return to the same view and display a validation error to the user like this:
I'm not sure how 'proper' this is but I can't currently think of a better way to handle this (E.G. even if I caught this in my DbContext derived class and threw a more specific exception I would still need to handle it in the controller in order to do anything with it at runtime).
I'm also not sure if I need to check the inner exception. I modified the code from this post which basically checks for a SqlException in the inner exceptions and checks the error number (in this case 2627 which is a unique key constraint) before reporting it to the user. If the SQL error number is something else a generic error message is displayed instead.
Update:
I now handle exceptions in a domain service class which is a derivative of the example shown here which allows me to handle the exception outside of the controller.

JPA not insert the data in the row after persist

I am using an ID generated value in my entity
#Id
#TableGenerator(
name="marcaTable",
table="JPA_WXS_APP_SEQUENCE_GENERATOR",
pkColumnName="GEN_KEY",
valueColumnName="GEN_VALUE",
pkColumnValue="MARCA_ID",
allocationSize=1,
initialValue=0)
#GeneratedValue(strategy=GenerationType.TABLE,generator="marcaTable")
public int getId() {
return Id;
}
I use a table to save the id.
If I execute this code twice its fail because there are duplicates ID (1 id)
public static void main(String[] args) {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("ACoches");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
marca nmarca2 = new marca();
nmarca2.setNombre_marca("pepito");
em.flush();
em.persist(nmarca2);
tx.commit();
em.close();
emf.close();
}
}
But if I manually execute a select of marca table it is empty, it seems that JPA dont insert the data in the row just when i make the em.persist(nmarca2);
If I delete the JPA_WXS_APP_SEQUENCE_GENERATOR table manually and I select again the marca table now yes I can see the register.
Thanks in advance!!!
persist() just registers the object to be persisted. It will not be inserted until commit() or flush(). If you call flush() after the persist() it will have been inserted.
Can't see why you would get a duplicate id. Turn logging on finest to see what SQL is being executed.
One issue may be your initialValue=0, try removing or changing it to 1.

JPA #GeneratedValue on id

In JPA, I am using #GeneratedValue:
#TableGenerator(name = "idGenerator", table = "generator", pkColumnName = "Indecator" , valueColumnName = "value", pkColumnValue = "man")
#Entity
#Table(name="Man")
public class Man implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "idGenerator")
#Column(name="ID")
private long id;
public void setId(Long i) {
this.id=i;
}
public Long getId(){
return id;
}
}
I initially set the ID to some arbitrary value (used as a test condition later on):
public class Sear {
public static void main(String[] args) throws Exception {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testID");
EntityManager em = emf.createEntityManager();
Man man = new Man();
man.setId(-1L);
try {
em.getTransaction().begin();
em.persist(man);
em.getTransaction().commit();
} catch (Exception e) { }
if(man.getId() == -1);
}
}
}
What is the expected value of man.id after executing commit()? Should it be (-1), a newly generated value, or I should expect an exception?
I want to use that check to detect any exceptions while persisting.
What is the expected value of man.id after executing commit()? Should it be (-1), a newly generated value, or I should expect an exception?
You are just not supposed to set the id when using GeneratedValue. Behavior on persist will differ from one implementation to another and relying on this behavior is thus a bad idea (non portable).
I want to use that check to detect any exceptions while persisting.
JPA will throw a (subclass of) PersistenceException if a problem occurs. The right way to handle a problem would be to catch this exception (this is a RuntimeExeption by the way).
If you insist with a poor man check, don't assign the id and check if you still have the default value after persist (in your case, it would be 0L).
You setting the value of a field that is auto-generated is irrelevant. It will be (should be) set by the JPA implementation according to the strategy specified.
In EclipseLink this is configurable using the IdValidation enum and the #PrimaryKey annotation or the "eclipselink.id-validation" persistence unit property.
By default null and 0 will cause the id to be regenerated, but other values will be used. If you set the IdValidation to NEGATIVE, then negative numbers will also be replaced.
You can also configure your Sequence object to always replace the value.