Error when try to insert value in database with NPoco - c#

I am using this example from Umbraco docs and when i try to save values to the database table i am getting this error:
Cannot insert the value NULL into column 'Id', table 'petapoco.dbo.BlogComments'; column does not allow nulls. INSERT fails. The statement has been terminated.
Also, after table is created and i check it in database, I can see that primary key and autoincrement option is not set for id field.
And this is how i insert values:
public class Class1 : IUserComposer
{
public void Compose(Composition composition)
{
composition.Components().Append<SubscribeToContentServiceSavingComponent>();
}
public class SubscribeToContentServiceSavingComponent : IComponent
{
public void Initialize()
{
MemberService.Saved += MemberService_Saving;
}
public void Terminate()
{
}
private void MemberService_Saving(IMemberService sender, SaveEventArgs<IMember> e)
{
foreach (IMember member in e.SavedEntities)
{
var blogPostToAdd = new BlogCommentSchema();
blogPostToAdd.BlogPostUmbracoId = member.Id;
blogPostToAdd.Name = member.Name;
blogPostToAdd.Email = member.Name;
blogPostToAdd.Website = member.Name;
blogPostToAdd.Message = member.Name;
using (var scope = Current.ScopeProvider.CreateScope(autoComplete:true))
{
var database = scope.Database;
// use database
scope.Database.Insert<BlogCommentSchema>(blogPostToAdd);
scope.Complete();
}
}
}
}
}

Good guy on Umbraco forum solved my problem. This is the missing part in my class:
[PrimaryKeyColumn(AutoIncrement = true, IdentitySeed = 1)]
So my class finally should look like this:
[TableName("BlogComments")]
[PrimaryKey("Id", AutoIncrement = true)]
[ExplicitColumns]
public class BlogCommentSchema
{
[PrimaryKeyColumn(AutoIncrement = true, IdentitySeed = 1)]
[Column("Id")]
public int Id { get; set; }
[Column("BlogPostUmbracoId")]
public int BlogPostUmbracoId { get; set; }
[Column("Name")]
public string Name { get; set; }
[Column("Email")]
public string Email { get; set; }
[Column("Website")]
public string Website { get; set; }
[Column("Message")]
[SpecialDbType(SpecialDbTypes.NTEXT)]
public string Message { get; set; }
}
}

Related

How to define a type whose gender can be changed on the fly in code without changing the type of all the properties that are of its type?

I have many entities that use a UserId property of the same type.
Can I define a type (string or int, ...) that I can easily change as a variant for all?
Example:
public class Entity_One
{
public DefineMyType UserId { get; set; }
public string Property_Entity_One { get; set; }
}
public class Entity_Two
{
public DefineMyType UserId { get; set; }
public string Property_Entity_Two { get; set; }
}
const DefineMyType = string;
// or const DefineMyType = int;
// or const DefineMyType = Guid;
Constants can't be used like that.
Preprocessor may be used.
But we can use a generic:
public abstract class AbstractID<T>
{
static protected T Last = default;
public T Value { get; protected set; } // or perhaps init only with C# 9
}
Thus we can define some specialized IDs like:
public class NumberID<T> : AbstractID<T> where T : struct, IComparable, IFormattable
{
public NumberID()
{
Value = (T)( (dynamic)Last + 1 );
Last = Value;
}
}
public class GuidID : AbstractID<Guid>
{
public GuidID()
{
Value = Guid.NewGuid();
Last = Value;
}
}
public class StringID : AbstractID<string>
{
private string Generate()
{
return ...
}
public StringID()
{
Value = Generate();
Last = Value;
}
}
Then we can set the "default" ID type:
public class ManagedID : NumberID<int>
{
}
Or:
public class ManagedID : GuidID
{
}
Therefore we can easily change ManagedID for all code using it.
It only requires to change the ancestor class in the declaration.
And now that works:
public class EntityOne
{
public ManagedID UserId { get; } = new ManagedID();
public string PropertyEntityOne { get; set; }
}
public class EntityTwo
{
public ManagedID UserId { get; } = new ManagedID();
public ManagedID EntityOneId { get; }
public string PropertyEntityTwo { get; set; }
public EntityTwo(EntityOne one)
{
EntityOneId = one.UserId;
}
}
Test
var entity1 = new EntityOne();
var entity2 = new EntityOne();
var entity3 = new EntityTwo(entity1);
Console.WriteLine(entity1.UserId.Value);
Console.WriteLine(entity2.UserId.Value);
Console.WriteLine(entity3.UserId.Value + $" ({entity3.EntityOneId.Value})");
Result with an integer
1
2
3 (1)
Result with a GUID
3a189122-60fd-4dc5-9d7f-3cc4c83375f9
37a9c7de-8ed5-4d02-a1b9-f414db051335
2de962d6-cc91-4e78-b3dc-28acb0ba7f3b (3a189122-60fd-4dc5-9d7f-3cc4c83375f9)
Warning
Here, the use of numbers is very basic and not really reliable, especially beyond a local machine and after stopping the execution of the current process. Thus persistence somewhere of the last value is required for a real database, like in a config file or whatever.
GUID vs INT IDENTITY
Guid vs INT - Which is better as a primary key?
Int for identity/primary key and Guid for public identifier, best practices?

How to insert graph in Entity Framework with circular dependency

This is how database structure looks like:
Vehicle has lot of CanNetworks and each CanNetwork has lot of ECUs. And that would save perfectly if that was only I have.
But, each vehicle also has one special ECU called gatewayECU so problem happens with saving because entity framework core does not know how to handle that scenario. It needs to insert vehicle before inserting ecus, but how to insert vehicle when ecu is not inserted.
This is what I tried: ignore (delete, invalidate) gatewayecu field (column is nullable in database), then I insert whole graph and then update vehicle with gatewayEcuId field I stored in some variable before doing anything.
Solution is not pretty. How to handle this scenario.
public class Vehicle : BaseEntity
{
public Vehicle()
{
CANNetworks = new List<CANNetwork>();
}
public List<CANNetwork>? CANNetworks { get; set; }
public ECU? GatewayECU { get; set; } = default!;
public int? GatewayECUId { get; set; }
}
public class CANNetwork : BaseEntity
{
public CANNetwork()
{
ECUs = new List<ECU>();
}
public string Name { get; set; } = default!;
public ICollection<ECU>? ECUs { get; set; }
public int VehicleId { get; set; }
public Vehicle? Vehicle { get; set; } = default!;
}
public class ECU : BaseEntity
{
public int CANNetworkId { get; set; }
public CANNetwork? CANNetwork { get; set; } = default!;
}
This is ugly solution which I don't want:
public async Task<int> Insert(Vehicle vehicleDefinition, ECU vehicleGatewayECU)
{
var result = -1;
using (var transaction = _databaseContext.Database.BeginTransaction())
{
result = await Insert(vehicleDefinition);
if (vehicleGatewayECU != null)
{
var ecu = await _databaseContext.ECUs.FirstOrDefaultAsync(x => x.Name == vehicleGatewayECU.Name && vehicleDefinition.Name == x.CANNetwork.Vehicle.Name);
if (ecu != null)
{
vehicleDefinition.GatewayECUId = ecu.Id;
result = await Update(vehicleDefinition);
transaction.Commit();
return result;
}
}
else
{
transaction.Commit();
}
}
return result;
}
EDIT:
I am now thinking about changing table structure in a way to get rid of gatewayECU field on Vehicle, and put some flag IsGatewayEcu in ECU table

How to drop table in Xamarin from sqlite database

I am unable to drop tables completely from sqLite database in XAMARIN using command db.DropTable<tablename>. It gets dropped at first but appears again every time I restart the application. Also I have multiple tables with the same name and I need to drop them all. What should I do?
I am developing an android application in Visual Studio using XAMARIN and C#.
Unfortunately I created many tables with the same name. Now I need to drop them.
I am using following code to create tables and database:-
namespace Test
{
[Table("OrderDetails")]
public class OrderDetails
{
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
[MaxLength(50)]
public string payeename { get; set; }
[MaxLength(100)]
public string commodity { get; set; }
public int give { get; set; }
public int take { get; set; }
public DateTime date { get; set; }
}
[Activity(Label = "Test", MainLauncher = true)]
public class MainActivity : Activity
{
[Table("Items")]
public class PayeeMaster
{
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
[MaxLength(8)]
public string FirstName { get; set; }
[MaxLength(8)]
public string LastName { get; set; }
}
SQLiteConnection db;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
CreateDatabase();
}
public bool ifExists_Table(string tablename)
{
SQLiteCommand command = db.CreateCommand("SELECT COUNT(1) FROM SQLITE_MASTER WHERE TYPE = #TYPE AND NAME = #NAME");
command.Bind("#TYPE", "table");
command.Bind("#NAME", tablename);
int result = command.ExecuteQuery<int>();
return (result > 0);
}
public void CreateDatabase() {
try
{
string dbPath = Path.Combine(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal),
"Master.db3");
db = new SQLiteConnection(dbPath);
}
catch (IOException ex)
{
var reason = string.Format("The database failed to create -
reason {0}", ex.Message);
}
if (!ifExists_Table("PayeeMaster"))
{
db.CreateTable<PayeeMaster>();
}
else
{
var count = db.Table<PayeeMaster>().Count();
}
if (!ifExists_Table("OrderDetails"))
{
db.CreateTable<OrderDetails>();
}
else {
var count = db.Table<OrderDetails>().Count();
}
}
}
I finally understand the problem, sorry for the confusion.
First of all - doing Table<T>().Count() doesn't actually check for table existence, but instead checks if the table contains any rows.
To actually check if the table exists, you will have to do an actual SQL query:
private bool DoesTableExist(string name)
{
    SQLiteCommand command = _connection.CreateCommand("SELECT COUNT(1) FROM SQLITE_MASTER WHERE TYPE = #TYPE AND NAME = #NAME");
    command.Bind("#TYPE", "table");
    command.Bind("#NAME", name);
    int result = command.ExecuteScalar<int>();
    return (result > 0);
}

Error inserting record with entity framework

I am sorry if it has already been answered but I can't find any solution. Here is my (little) problem. Also all my apologies if the terms I use are approximate, I am far from being a skilled C# developer
Note that I think my problem is similar to this one Entity Framework validation error for missing field, but it's not missing?
I have a table "Tweets" with a tweet_id field (bigint) which is my primary key.
I use the following class to load the table :
class TwitterDbContext : DbContext
{
public TwitterDbContext() : base("Twitter")
{
}
public DbSet<Stream> Streams { get; set; }
public DbSet<StreamParameter> StreamParameters { get; set; }
public DbSet<Tweet> Tweets { get; set; }
}
public class Tweet
{
public Tweet()
{
}
[Key]
public long tweet_id { get; set; }
public string tweet { get; set; }
public long creator { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public string language { get; set; }
public DateTime created_at { get; set; }
public DateTime registered_at { get; set; }
public long? in_reply_to { get; set; }
public bool retweeted { get; set; }
}
I have an other class to store within the code execution all the fields used by the Tweet table. For the need here, let's imagine I manually create it that way
private void Test_Button_Click(object sender, RoutedEventArgs e)
{
Twts twtReceived = new Twts();
twtReceived.tweet_id = 1;
twtReceived.tweet = "test";
twtReceived.creator = 1;
twtReceived.latitude = -1;
twtReceived.longitude = -1;
twtReceived.language = "a";
twtReceived.created_at = DateTime.Now;
twtReceived.registered_at = DateTime.Now;
twtReceived.in_reply_to = 1;
twtReceived.retweeted = true;
AddTweet(twtReceived);
}
Now here is the AddTweet method
static public void AddTweet(Twts twtReceived)
{
try
{
// update the tweet data in the database
using (var TwitterDb = new TwitterDbContext())
{
Tweet twt = new Tweet()
{
tweet_id = twtReceived.tweet_id,
tweet = twtReceived.tweet,
creator = twtReceived.creator,
longitude = twtReceived.longitude,
latitude = twtReceived.latitude,
language = twtReceived.language,
created_at = twtReceived.created_at,
registered_at = twtReceived.registered_at,
in_reply_to = twtReceived.in_reply_to,
retweeted = twtReceived.retweeted
};
TwitterDb.Tweets.Add(twt);
TwitterDb.SaveChanges();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.InnerException.ToString());
}
}
I constantly have the same error message:
Cannot insert the value NULL into column 'tweet_id', table
'Twitter.dbo.Tweets'; column does not allow nulls. INSERT fails.
The thing is that when I spy on "TwitterDb.Tweets.Local" after TwitterDb.Tweets.Add(twt); I correctly have tweet_id set to 1.
Any idea where is the issue?
Try marking your tweet_id field with following (instead of just [Key]), if this is a primary key column where you want to provide values yourself
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
If it is an auto-increment, then remove explicit assignments to this field and mark it as 'Identity' instead:
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]

Specified table does not exist

I'm searching for an answer to this question. I don't know where is the problem. Visual Studio does not see any problem or error, but when I run program and try to add something to database, application crashes and VS tell me that my table does not exist. That event is for adding something.
This is my code:
private void addBtn_Click(object sender, RoutedEventArgs e)
{
using (WpisyDataContext BazaDanych = new WpisyDataContext(strConnectionString))
{
if (!BazaDanych.DatabaseExists())
{
BazaDanych.CreateDatabase();
MessageBox.Show("BazaDanych Database Created Successfully!!!");
}
Wpis newWpis = new Wpis
{
RecordID = index_box.Text,
NameRec = name_box.Text.ToString(),
BeneficiaryRec = beneficiary_box.Text.ToString(),
PriceRec = price_box.Text.ToString(),
DeadlineRec = deadline_box.Text.ToString(),
DescriptionRec = description_box.Text.ToString()
};
BazaDanych.Wpisy.InsertOnSubmit(newWpis);
BazaDanych.SubmitChanges();
MessageBox.Show("Recoed Added Successfully!!!");
if (NavigationService.CanGoBack)
{
NavigationService.GoBack();
}
}
}
}
This is the table code (Wpis.cs):
using System.Data.Linq.Mapping;
namespace ********
{
[Table]
public class Wpis
{
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public string RecordID
{
get;
set;
}
[Column(CanBeNull = true)]
public string NameRec
{
get;
set;
}
[Column(CanBeNull = true)]
public string BeneficiaryRec
{
get;
set;
}
[Column(CanBeNull = true)]
public string PriceRec
{
get;
set;
}
[Column(CanBeNull = true)]
public string DeadlineRec
{
get;
set;
}
[Column(CanBeNull = true)]
public string DescriptionRec
{
get;
set;
}
}
}
And this is the data context (WpisyDataContext.cs):
using System.Data.Linq;
namespace *************
{
public class WpisyDataContext : DataContext
{
public WpisyDataContext(string connectionString)
: base(connectionString)
{
}
public Table<Wpis> Wpisy
{
get
{
return this.GetTable<Wpis>();
}
}
}
}
This is connection string:
public static string strConnectionString = #"Data Source=isostore:/DevDB.sdf";
Please guys, I don't have any more patience. Thanks.
When you use CreateDatabase(), please check whether .Net has created the database table as your Entity. Because EntityFramework create table with Plural name and Entity is created with singular name.
Check whether the created table name is as expected.

Categories

Resources