I have an EF5 code first project that uses the [DatabaseGenerated(DatabaseGeneratedOption.Computed)] attribute.
This option is overriding my settings.
Consider this SQL table:
CREATE TABLE Vehicle (
VehicleId int identity(1,1) not null,
Name varchar(100) not null default ('Not Set')
)
I am using the SQL default construct to set the [Name] is case it is not set.
In code behind, I have a class defined similar to:
public class Vehicle {
...
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string ShoulderYN { get; set; }
}
When I update the entity in code, the value set in the default overrides my new setting.
In code, I have (pseudo):
vehicle.Name = 'Update Name of Vehicle';
_dbContext.Update(vehicle);
_dbContext.SaveChanges();
The expected result is Vehicle.Name = 'Update Name of Vehicle'.
The actual result is Vehicle.Name = 'Not Set'.
Is there a way in EF5 to say:
if Vehicle.Name is null/empty, use the value defined in the database? Otherwise, if I set the value in code, I want to use this value.
Apparently, no there isn't. It's not that smart :)
As you may already read, Computed option just tells the EF not to update your column, because you will compute a value on the DB-side yourself. EF will then just return newly computed value from your database (which in your case is "Not Set").
Your basic three options are - as per EF Source code documentation:
None - The database does not generate values.
Identity - The database generates a value when a row is inserted.
Computed - The database generates a value when a row is inserted or updated.
https://github.com/aspnet/EntityFramework6/blob/527ae18fe23f7649712e9461de0c90ed67c3dca9/src/EntityFramework/DataAnnotations/Schema/DatabaseGeneratedOption.cs
Since you expect a little more custom logic to be done, I'm afraid you would have to do it yourself. I would suggest you stop relying on database default constraint and do everything in code first approach. This way you would have a code like that:
public class Vehicle
{
public Vehicle()
{
this.Name = "Not set";
}
// Without 'Generated' attribute
public string Name { get; set; }
}
This way, when your Entity is created, it automatically starts with expected default value. And can be later changed by simply modifying the Name property.
Hope it helps!
Actually there is a simple solution for this:
You need to leave default constraint with value in table creation script as it is now:
CREATE TABLE Vehicle (
VehicleId int identity(1,1) not null,
Name varchar(100) not null default ('Not Set')
)
Just remove DatabaseGenerated attribute from property in class definition:
public class Vehicle {
...
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string ShoulderYN { get; set; }
}
And that's it: now database will use default value only if you do not specify some value in code. Hope this helps.
I checked this for hours to get good answer but no:
EF cannot update models by automatic generated-ID.
You have 3 options:
Adding another VehicleId to Vehicle model.
Change automatic generated-ID to be manual generated by you.
Setting unique identifier to be something else then the generated-ID in your
model.
In your Vehicle Class it can be the Name property.
I suggest you option 3:
Setting up unique-id to be Vehicle.Name (and you can add more properties).
Then: if vehicle by unique-id doesn't exists, add new vehicle to db-context:
//if there is no such a Vehicle in system, add it:
if (vehicle.Name !=null && vehicle.Name != String.Empty && _dbContext.Where(v => v.Name == vehicle.Name).FirstOrDefault() == null)
_dbContext.Add(vehicle);
_dbContext.SaveChanges();
Related
I've been trying to update an Entity using the following code:
var db = new MyContext();
var data = db.Tableau.Find(Id);
if (data != null)
{
data.Name = model.Name;
data.EmbedCode = model.EmbedCode;
db.SaveChanges();
}
The problem is that my Tableaus table has a Parent field (FK not null to a DataTree table). Sometimes when I save the changes to this edited record, I get an error saying that "The Parent field is required". But I am not editing the Parent field. The parent field should be intact and existent, since I am only altering the Name and EmbedCode fields.
How to proceed? Thanks in advance.
That is because you are allowing null values in ParentId column in your Tableaus table, but in your Tableau entity you have ParentId as non-nullable property( which it means the relationship is required), and when you load a Tableau instance from your DB, EF expects that you set that property too. Try changing that property to nullable:
public int? ParentId {get;set;}
If you configure your relationship using Fluent Api it would be:
modelBuilder.Entity<Tableau>()
.HasOptional(t=>t.Parent)
.WithMany(dt=>dt.Tablous)// if you don't have a collection nav. property in your DataTree entity, you can call this method without parameter
.HasForeignKey(t=>t.ParentId);
Update 1
If you want ParentId property as Required in your Tableau entity, you need to make sure that you have a valid value in that column in your DB per each row. With a "valid value" I mean it should be different of the default value and it should exist as PK in your DataTree table.
Update 2:
One way to load a related entity as part of your query is using Include extension method:
var data = db.Tableau.Include(t=>t.Parent).FirstOrDefault(t=>t.Id==Id);
I have an entity called Comment, which has an enum property of type CommentType:
public class Comment
{
public virtual Guid Id { get; private set; }
public virtual CommentType CommentType { get; set; }
// other prop removed for simplicity
}
public enum CommentType
{
Comment,
Correction,
Improvement,
BugFix,
NewFeauture,
Other
}
I need to select the comments from database by the alphabetically value of the CommentType enum, something like
_db.Comments.OrderBy(p => p.CommentType)
However, the Enum values are treated as integers, and the sort will not work alphabetically correctly.
Is there any way to add some attributes / metadata to the Enum values to make them sort correctly alphabetically?
One solution will be to assign the integer value to enum values, but i already have many database records that will need to be updated. And this solution is not good for new added enum values.
public enum CommentType
{
Comment = 2,
Correction = 3,
Improvement = 4,
BugFix = 1,
NewFeauture = 5,
Other = 6
}
Currently your enum name is not known at database level so in my opinion you have two options.
Use value on server side:
_db.Comments.ToList().OrderBy(p => p.CommentType.ToString())
Add value on database side: You should create table that will contain comment type names. And then you can create foreign key between comments and commentTypeNames and use simple select:
_db.Comments.OrderBy(c => c.CommentTypeNames.Name)
or just make join:
_db.Comments
.Join(
_db.CommentTypeNames,
c => c.CommentType,
ctn => ctn.CommentType,
(c, ctn) => new { Comment = c, CommentName = ctn })
.OrderBy(g => g.CommentName.Name)
.Select(g => g.Comment);
There are also computed columns. I never used those though so I dont have experience. Maybe you could add column that will be resolved to string by CASE statements on database. However I am not sure how will this affect performance/maintainability. For more info you could check http://geekswithblogs.net/DavidPaquette/archive/2012/09/23/calculated-columns-in-entity-framework-code-first-migrations.aspx
For performance reasons I would advise to take option 2, it's better to do such things in database.
I assume that you are using code first so maybe this post will be helpful for you: EF5 Code First Enums and Lookup Tables
This idea of a table is nice of course, especially when the enum has many values and is likely to get new ones. However, when enum values are added both the code and the database need to be maintained.
In general when the enum is volatile I would not use an enum but only the table.
But when it is not likely to change much, you could also consider to stick with the enum simply write out the order instruction:
_db.Comments.OrderBy(p =>
p.CommentType == CommentType.Comment ? "Comment" :
p.CommentType == CommentType.Correction ? "Correction" :
p.CommentType == CommentType.Improvement? "Improvement" :
.... :
"ZZZ")
As an alternative you may convert CommentType property in your Comment class into foreign key 'CommentTypeId' pointing at CommentType(Id, Name) table, that has your Id values and corresponding text Name.
This will let you order by text easily.
I have a WebForms applicaiton using the new ASP.NET Identity. I've added a couple of additional fields in the class to allow for Email and a Boolean called IsOnLine.
I use migrations, to explicititly update the tables, and can see that my new fields are there. However, whenever I try to login now i get the following error:
Additional information: The 'IsOnLine' property on 'ApplicationUser' could not be set to a 'null' value. You must set this property to a non-null value of type 'System.Boolean'.
All the exmamples on the net relate to MVC, which i'm not using yet.
How can i fix this?
A bool cannot be null so that is what is set to in the database. If you want it to be null you will need to define it as a nullable bool using the ? operator.
public class ApplicationUser : IdentityUser
{
public bool? IsOnline { get; set; }
}
To update this information in the database take a look at this article on adding email confirmation to ASP.NET Identity. In this example there is a boolean flag IsConfirmed that is updated during the registration process, which will be similar to your IsOnline flag. Here is a snippet of the relevant code to update the database.
user.IsOnline = true;
DbSet<ApplicationUser> dbSet = context.Set<ApplicationUser>();
dbSet.Attach(user);
context.Entry(user).State = EntityState.Modified;
context.SaveChanges();
I prefer to avoid null values whenever possible, to determine if a property can accept nulls values it is better to think what that information represents in the domain problem. In this case i think it not make sense to have an undetermined value for IsOnline because the user is online or offline, not middle terms apply to this fact.
To resolve this problem with the database, taking advantage that you are using Code Migration , you can use the Seed method from Configuration class and assing the value(s) to your new fields that are not nullable.
Pseudo code:
Seed()
for each user
set user IsOnline to false
I recently started working with ServiceStack and its ORMLite framework. I have searched on Google and browsed the source code but couldn't find anything relevent.
Is there any way to select specific columns when executing a query with ORMLite ?
Something like that : Db.First<Model>(q => q.Id == someId, "Column1, Column2")
Unless I missed this feature, I am surprised nobody asked about this before, since this is one the rule of thumbs to optimize your DB transactions.
If you want to specify columns other that the table you need to use SQL as seen in this earlier example
So in your case you could do something like:
Db.First<Model>("SELECT Column1, Column2 FROM AnyTableOrView");
You can also create a partial model that looks at your table by decorating it with the [Alias] attribute, like:
[Alias("AnyTableOrView")]
public class Model {
public int Id { get; set; }
public string Column1 { get; set; }
public string Column2 { get; set; }
}
Then you can do something like:
Db.First<Model>(q => q.Id == someId);
And it will only SELECT + populate fields from the partial model.
I did try this :
Created a Database VIEW (table name and columns are already set)
Created a class named "Event" and matching each fields for that table with a property
(i used [Alias] for table name and for all columns to have nice names)
Wrote access to DB to select 1 record based on it's ID
var dbFactory = new OrmLiteConnectionFactory(
"Data Source=MyDB;User Id=user;Password=pwd", // Connection String
OracleDialect.Provider);
using (var db = dbFactory.OpenDbConnection())
{
var event = db.GetByIdOrDefault<Event>( request.Id );
}
At that point the var 'event' is populated but only the Id field is filled !
all the others fields of the class are not filled (while there are really data in database).
It's the simplest i can do and it does not work. Any ideas ?
(PS : i am using OrmLite for Oracle)
Thanks
I have found the problem.
It was due to an incorrect type matching between field in my class (defined as a string) and the corresponding Oracle Field (that is a DATE).
I replaced the string with datetime and worked like a charm.
So it's working perfectly with a VIEW and that's GREATLY simplify the code.
I had a similar problem, however my solution was different.
I had a int property in my POCO. My query (from Oracle) was returning a null for this property. It caused a exception to be raised and prevented further processing of that row.
The result was a partial populated POCO.
The solution was to change to type to be nullable.
public int? mypropperty
When I query from the entity framework I always query in a detached state so that the records retrieved can be stored in cache for subsequent requests.
Right now I have a form that the user can edit which contains a parent record, and then two lists of parent records.
When the data is POSTed to the server, I take my view models and map them into the entity framework objects using AutoMapper. The data looks fine; AutoMapper is mapping the data correctly.
When I attach the object so that I can update it, an exception is thrown: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
//Exception happens here
orderContext.ShippingOrders.Attach(shippingOrder);
//Update the order itself; mark the order has being modified so the EF will update it.
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, System.Data.EntityState.Modified);
//Perform the update.
orderContext.SaveChanges();
}
}
The EntityFramework (EF) seems to think that my keys aren't lining up, but I'm not sure what isn't correct. The foreign key property does have the correct value, so I'm not sure what it's checking. Does anyone have any ideas?
You might try something like this:
ShippingOrder existingShippingOrder = orderContext.ShippingOrders.Find(shippingOrder.ID);
orderContext.Entry(existingShippingOrder ).CurrentValues.SetValues(shippingOrder);
Instead of
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, System.Data.EntityState.Modified);
try this
orderContext.Entry(ShippingOrder).State = EntityState.Modified;
as explained here
Insert or update pattern A common pattern for some applications is to
either Add an entity as new (resulting in a database insert) or Attach
an entity as existing and mark it as modified (resulting in a database
update) depending on the value of the primary key. For example, when
using database generated integer primary keys it is common to treat an
entity with a zero key as new and an entity with a non-zero key as
existing. This pattern can be achieved by setting the entity state
based on a check of the primary key value. For example:
public void InsertOrUpdate(DbContext context, Unicorn unicorn)
{
context.Entry(unicorn).State = unicorn.Id == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
you can try
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
orderContext.Entry(shippingOrder).State = shippingOrder.Id==0?
EntityState.Added :
EntityState.Modified;
orderContext.SaveChanges();
}
}
UPDATE:
for ObjectContext class you can try
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, EntityState.Modified);
orderContext.SaveChanges();
}
}