Can't retrieve auto generated primary key using Vici Coolstorage - sqlite

I'm using Vici Coolstorage in a Windows Forms project to access a SQLite database. In every table in my database there is a field called ID defined as INTEGER PRIMARY KEY, so it is an auto increment field.
I'm trying to retrieve the value of that field after I store the object in the database, but I always get the value 0 instead of the real ID. The Vici Coolstorage documentation states that "if the primary key is defined as an autonumber (identity) field in the database, your can retrieve the generated primary key after the object is saved", but that doesn't seem to be true unless I'm doing something wrong. Please help me. This code will reproduce the problem:
<MapTo("Company")> Public MustInherit Class Company
Inherits CSObject(Of Company, Integer)
Public MustOverride ReadOnly Property ID As Integer
Public MustOverride Property Name As String
End Class
Sub SomeMethod()
Dim C As Company = Company.[New]
C.Name = "Some name"
C.Save()
MessageBox.Show(C.ID) 'This always prints 0!!!
End Sub
Thank you!

Had faced this issue and figured out that setting the identity attribute on the field solved this.
[Identity]
public int Id
{
get { return (int)GetField("Id"); }
}

Related

SqlException with Creating User, after changing IdentityUser primary key from string to int

After I've followed this to change the type of Application User Id from string to int, I get SqlException if I try to create a new user.
The exact error is:
Cannot insert the value NULL into column 'Id' table 'DBNAME.dbo.AspNetUsers'; column does not allow nulls. INSERT fails. The statement has been terminated.
Line 208: };
Line 209:
Line 210: var result = await UserManager.CreateAsync(user, model.Password);
Line 211: if (result.Succeeded)
Line 212: {
Source File: C:\Projects\ProjectName\ProjectName\Controllers\MembersController.cs Line: 210
[SqlException (0x80131904): Cannot insert the value NULL into column 'Id', table 'DBNAME.dbo.AspNetUsers'; column does not allow nulls. INSERT fails.
The statement has been terminated.]
Here is the screenshot of AspNetUsers table design view:
I've looked at How to tell the primary key 'Id' of IdentityUser class is IDENTITY(1,1)?
and ASP.NET Identity - Error when changing User ID Primary Key default type from string to int AND when using custom table names but couldn't help me much.
Any help is very much appreciated.
Your problem that Identity is no longer generating a key for you - it did before.
For this problem to work you need to get the key automatically generated by a database. To get this done you need to apply the following attributes on your Id property in ApplicationUser class:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int Id { get; set; }
And add another DB-migration to make sure the database knows what to do with this field.
UPD: oops. Just noticed that you already link to my identical answer. Does this not help?

PetaPoco \ NPoco - Partial Insert

Is there a way to partially insert an object using PetaPoco or NPoco?
For example, I have a table called Users:
UserId | UserName | UserMail | UserCreationDate
Each one of these columns are NON NULLABLE and have a default value when they are left empty.
In ASP.NET I have a User class, and I use the ORM to insert a new record with only the name:
Dim userData As New User()
userData.UserName = "Jimmy Hendrix"
db.Insert(userData)
I expect the database to look as follows:
UserId | UserName | UserMail | UserCreationDate
12 | Jimmy Hendrix | (DB default)| (DB default)
I want the insert command only insert the name, without inserting the other object properties with the object's default values.
Such as there is a partial update, I want a partial insert.
Is that possible in PetaPoco?
Is there another way to do it by myself without any ORM?
Edit:
Using SQL I can get the job done, but I need to use POCO objects, so I don't want to have to remember the database parameters. I want something like
user.UserName = "Michael"
user.Insert(user)
And it will insert only the UserName, ignoring the other variables. The SQL that I want to be generated in the background is:
"INSERT Users(UserName) VALUES(#UserName)"
(while the #UserName parameter holds the userData.FirstName value)
As you can see, it doesn't take in account the other variables in the class.
Today if I use the insert command, even if I give a value to a single property in the class, NPoco still tries to insert ALL the class variables into the db setting the variables I didn't want to set with the class's default values (which are different from the db default values)
Also, all of the properties are insertable/updateable, so there can't be any ResultColumn types in the class. I want to insert these values but only the ones I declare in that particular instance. All of the properties are available to update and insert but for each instance i insert only what i declare.
I would create a PartialUserForInsert class:
[TableName("Users")]
public class PartialUserForInsert
{
public string UserName { get; set; }
}
Your provided schema does not include a FirstName column.
Assuming the column is mapped to UserName, using the following should insert as expected.
dim sql = new Sql("INSERT Users(UserName) VALUES(#0)", userData.FirstName)
db.Execute(sql)

How to manage multiple connections for different users

i am working on a CMS solutions for real estate agencies.
so different users/groups will use the same tool.
i created 1 asp.net membership Database where i manage ALL users.
The users are grouped in different roles.( 1 role = 1 agency office)
Then - for every group i have another Database. In this database i manage the real estates and customers of the given office. (These Databases have the same structure.)
Currently i am using the "custom ASP.NET Profile class" where i store the connectionsstring for the specific database. I create this custom profile if the user logs in.
Now i have the problem, if an anonymous user is visiting the page ( there is a public section ) i get connectionstring errors cause there is no "custom profile" where my functions can read the connectionstring
My Custom Profile Class looks like:
Public Class UserProfile
Inherits ProfileBase
Public Shared Function GetUserProfile(username As String) As UserProfile
Return TryCast(Create(username), UserProfile)
End Function
Public Shared Function GetUserProfile() As UserProfile
Return TryCast(Create(Membership.GetUser().UserName), UserProfile)
End Function
<SettingsAllowAnonymous(False)> _
Public Property role() As String
Get
Return TryCast(MyBase.Item("role"), String)
End Get
Set(value As String)
MyBase.Item("role") = value
End Set
End Property
<SettingsAllowAnonymous(False)> _
Public Property UsersCustomConnectionString() As String
Get
Return TryCast(MyBase.Item("UsersCustomConnectionString"), String)
End Get
Set(value As String)
MyBase.Item("UsersCustomConnectionString") = value
End Set
End Property
End Class
Then i can read my connection string like
Dim currentprofile As UserProfile = UserProfile.GetUserProfile()
Dim strcon As String = currentprofile.UsersCustomConnectionString
How could i solve this issue ?
Or should i use another way to solve the "many connection strings" issue ? if yes, how ? (i think session varaiables won't work)
Thanks in advance
This is what we do: put in web.config an entry for each connection string in the
<appSettings>
section like this:
<add key="connection_string_key" value="YourDBServerConnectionString"/>
Then you read the value from your db access class like this:
System.Configuration.ConfigurationManager.AppSettings[connection_string_key]
And if you want to change them dynamically make some factory class where you read them all and return the right connection string based on the role of the current user or if they are logged in or not.

Entity Framework 5: Using DatabaseGeneratedOption.Computed option

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();

Entity Framework (Loading Nested Entities)

These are my entities...
Public Class Account
Public Property AccountId As Integer
Public Property AccountDescription As String
Public Property Transactions As List(Of Transaction)
End Class
Public Class Transaction
Public Property TransactionId As Integer
Public Property AccountId As Integer
Public Property TransferAccountId As Integer
Public Property TransactionDescription As String
End Class
I now know I can do this. db.Account.Include("Transactions").SingleOrDefault(Function(a) a.AccountId = myAccountId)
However this only includes the transactions that have AccountId = myAccountId obviously. But in my case i want all transactions, including those that are involved in a transfer. so where AccountId = AccountId or TransferAccountId = myAccountId. How can i load an account and its list of transactions and transfertransactions in one call?
With your model you cannot do that directly because you have only single Transaction property on Account class. This property will point either to accounts with AccountId == Id or TransferAccountId == Id but never to both. If you want to easily load both types you need two navigation properties on your Account type - one for related transaction and one for transfer transaction, after that you will just use Include for both properties:
db.Account.Include("Transactions")
.Inclue("TransferTransactions")
.SingleOrDefault(Function(a) a.AccountId = myAccountId)
If you don't want to add second navigation property you can do it in reverse direction. Query transactions and eager load account. As a last case you can query account and transactions separately.

Resources