Set default datetime value with PetaPoco - datetime

I have a PetaPoco class which defines a database table. It looks like this:
namespace MyProject.Pocos
{
[TableName("AdminNotification")]
[PrimaryKey("id", autoIncrement = true)]
[ExplicitColumns]
public class AdminNotification
{
[Column("id")]
[PrimaryKeyColumn(AutoIncrement = true)]
public int id { get; set; }
[Column("dateTime")]
public DateTime dateTime { get; set; }
[Column("adminNotificationTypeId")]
public int adminNotificationTypeId { get; set; }
}
}
It works great except for one thing. In the database table itself (in SQL Server Express) there is a default value set for 'dateTime' - it defaults to (getdate()). However, when record is inserted using the PetaPoco class in my code, the value of dateTime is always NULL.
How can I set the default value in the PetaPoco class to the current date/time?
Thanks!

One way is to add a constructor and set the default value there:
[TableName("AdminNotification")]
[PrimaryKey("id", autoIncrement = true)]
[ExplicitColumns]
public class AdminNotification
{
[Column("id")]
[PrimaryKeyColumn(AutoIncrement = true)]
public int id { get; set; }
[Column("dateTime")]
public DateTime dateTime { get; set; }
[Column("adminNotificationTypeId")]
public int adminNotificationTypeId { get; set; }
public AdminNotification(){
dateTime = DateTime.Now;
}
}
Depending on the way you create and insert the object, the value will be showing the time of creation of the AdminNotification, not the time it has actually been written to the database, but most of the time the difference is negligible and won't make a difference.

Related

Creating a "Goal" Tracker for an existing project

I have a current MVC project that is near enough complete for the basic aspects. The project tracks my progress throughout my running and weight loss as I find a lot of apps out there a bit bloated.
I have some basic models:
Distance:
public class Distance
{
public int Id { get; set; }
[DisplayName("Distance Run")]
public double DistanceRun { get; set; }
[DisplayName("Choose a date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime _Date { get; set; }
[DisplayName("Any Addtional Comments")]
public String AdditionalComments { get; set; }
}
Weight:
{
public int Id{ get; set; }
[DisplayName("Current Weight")]
public double CurrentWeight { get; set; }
[DisplayName("Chose a date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime _Date { get; set; }
[DisplayName("Any Addtional Comments")]
public String AdditionalComments { get; set; }
}
how would I go about creating a type of Goal creator for each one of these models. When I mean goal I mean "x amount run by y date"
I would try a possible Goal Model that would have fields similar to:
Goal:
public class Goal
{
public int Id { get; set; }
public virtual double goalValue { get; set; }
public DateTime dateTime { get; set; }
}
My issue lies where to differentiate whether the goal is either for DIstance run or Weight Lost/Gained. Am I on the right lines or should I reconsider and not use a model?
I would suggest using inheritance. Create a base class like:
public class Metric
{
[DisplayName("Chose a date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime _Date { get; set; }
[DisplayName("Any Addtional Comments")]
public String AdditionalComments { get; set; }
}
Then, have both Distance and Weight inherit from this:
public class Distance : Metric
{
}
public class Weight : Metric
{
}
Then, your Goal can have a foreign key to Metric:
public class Goal
{
...
public virtual Metric Metric { get; set; }
}
Based on how Entity Framework handles inheritance, it will actually instantiate Distance/Weight depending on which one was actually saved. The property value will be upcasted to Metric, though, so you'll need to cast to access the properties on your derived classes:
if (goal.Metric is Distance)
{
var distanceRun = ((Distance)goal.Metric).DistanceRun;
}
You can also simply use as and then check for null:
var distance = goal.Metric as Distance;
if (distance != null)
{
// do something with `distance`
}
Adding an ID to a reference table that differentiates the different types is a solution to the problem. I think from an MVC-side, inheritance isn't going to work because on postback, the framework won't know what type of object to create (Distance or Weight for instance). So while inheritance may work as #Chris suggested, on the MVC side you need a composite object with some identifying value to determine which type of object is. That's where a reference table can come in handy.
OR, create a view model for the MVC side, and not load and save raw EF objects directly. Doing that adds work, but can ensure the UI design doesn't entangle the database design.

Is ok to add [BsonAttribute] to POCOs?

I have an application, structured like this:
Application.Domain
Application.Web.Mvc
Application.MongoDb
In Application.Domain i keep all the POCOs of the application (the domain models).
public class Product
{
public string Id { get; set; }
public string ProductName { get; set; }
public DateTime CreatedDate { get; set; }
}
Now, because i am using MongoDb, i also need to use some of the [BsonAttribute], in order to customize the serialization process.
For example:
public class Product
{
[BsonId]
public string Id { get; set; }
public string ProductName { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Local, DateOnly = true)]
public DateTime CreatedDate { get; set; }
}
If i add these attributes, i will need to also add a reference to MongoDB.Bson.Serialization.Attributes in the Application.Domain project, which i want to avoid.
I think the correct way to do this is to create mapping objects in the Application.MongoDb project, and always map them from POCO to MongoObjects and the other way around every time i work with MongoDb repos.
If this is the correct solution, isn't this a bit overkill?

Entity Framework Many To Many allow duplicates

Is it possible to insert duplicate rows in Many to Many relationship? This is my class:
public class EventPaintballBundle
{
[Key, Column(Order = 0)]
public int EventID { get; set; }
[Key, Column(Order = 1)]
public int PaintballBundleID { get; set; }
public virtual Event Event { get; set; }
public virtual PaintballBundle PaintballBundle { get; set; }
[Range(1, Int32.MaxValue)]
public int PersonCount { get; set; }
[Required]
public DateTime Data { get; set; }
}
I want to insert second row of those values. The differences are on Date Date and PersonCount value
EventPaintballBundle xx = new EventPaintballBundle() { PaintballBundleID = 1, EventID = 155, Data = DateTime.Now, PersonCount = 5 };
dc.EventPaintballBundles.Add(xx);
dc.SaveChanges();
I'm getting error while I want to insert a duplicate of two keys.
{"Violation of PRIMARY KEY constraint 'PK_dbo.EventPaintballBundles'.
Cannot insert duplicate key in object 'dbo.EventPaintballBundles'. The
duplicate key value is (155, 1).\r\nThe statement has been
terminated."}
How to solve this problem?
Create a primary key that isn't the combination of :
public int EventID { get; set; }
public int PaintballBundleID { get; set; }
The new primary should be unique and not related to anything that actually exist, this key will exist only to make your model work database wise.
It's a classic mistake : to think your primary key should represent something that exist... NO
I learned it the hard way : even if i think that some combination of existing data will stay forever unique. I don't use it. I ALWAYS create my primary key from my own design, not representing anything real.

How to have default values for an attribute in Code First?

Basically I'm trying to expand on the already created SimpleMembership of ASP.NET MVC 4.
I wanna add a balance field that has the initial value of 0.
I've tried with the following code and inserting nothing in the Balance field:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string RealName { get; set; }
public int Balance { get; set; }
}
But unfortunately I get an exception when I try to create a new user (without a balance) that I cannot insert null in balance since it doesn't allow nulls.
How can I get balance to be 0 as a default value in Code First.
The
int Balance
does not allow nulls but
int? Balance
does.
If you want to controll the structure at the database level, use explicit migrations and manually tweak the generated migration code so that you set up a default value at the database level. If you want a default value at the code level, just set the value in the default constructor of the class.
First: You can use a constructor like this:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string RealName { get; set; }
public int Balance { get; set; }
public UserProfile()
{
this.Balance = 0;
}
}
Second, clean and rebuild solution, then use the migration command
Update-database -verbose
Integers have a default value of 0 by default. When you instantiate a new UserProfile, Balance should already be set to 0.
See: Default Values Table (C# Reference)

Getting "Cannot insert the value NULL into column" when trying to save with .Add() method using DbContext . Please check my POCO's and save method

Used code first and everything appears to work apart from the below which also worked before when I used ObjectContext and called context.PCBuilds.AddObject(pcBuild) but after switching to DbContext it's giving me the error.
EFDbContext context = new EFDbContext();
public ActionResult Index()
{
PCBuild pcBuild = new PCBuild();
pcBuild.BuildID = 34245;
pcBuild.BuildName = "Test99";
pcBuild.MarkUp = 25;
pcBuild.BDetails = new List<BDetail>();
context.PCBuilds.Add(pcBuild);
//repository.PCBuilds.Attach(pcBuild);
context.SaveChanges();
return View();
}
Giving me the: Cannot insert the value NULL into column 'BuildID', table 'C:\USERS\ADMIN\DOCUMENTS\VISUAL STUDIO 2010\PROJECTS\NEOCART\NEOCART.WEBUI\APP_DATA\NEODBX.MDF.dbo.PCBuilds'; column does not allow nulls. INSERT fails. Where as BuildID was clearly set before the SaveChanges is called. Appears that calling the .Add(pcBuild) doesn't add the populated object for some reason and when savechanges is called it attempts to insert an empty PCBuild ?
Here are the POCO's
public class PCBuild
{
[Key]
public int BuildID { get; set; }
public string BuildName { get; set; }
public string Socket { get; set; }
public decimal? MarkUp {get; set;}
[InverseProperty("PCBuild")]
public virtual ICollection<BDetail> BDetails { get; set; }
}
public class BDetail
{
[Key]
public int LineID { get; set; }
[ForeignKey("PCBuild")]
public int BuildID { get; set; }
[ForeignKey("Product")]
public int ProductID { get; set; }
public bool? IsSelected { get; set; }
[InverseProperty("BDetails")]
public virtual PCBuild PCBuild { get; set; }
[InverseProperty("BDetails")]
public virtual Product Product { get; set; }
}
Use StoreGeneratedAttribute on the PCBuild.BuildID property. It is not only a key but IDENTITY field.
UPDATE
Actually, it should be [DatabaseGenerated(DatabaseGenerationOption.Identity)] annotation. The article linked above describes early CTP version.
UPDATE 2
Wait, the key is being generated by the app, it is not an identity column in database? Change annotation to [DatabaseGenerated(DatabaseGenerationOption.None)], re-create the context and rebuild the application.
I'm not really familiar with the Code First approach, but could it be that when you specify the BuildID as being a [Key] field, it is setting it as an auto identity field in the database?
As such it may be blocking your attempt to write to it.
Try removing the [Key] identifier, then recreate the database. Can you then save the object ok?

Resources