I have been looking into Fluent Nhibernate, and it seems really promising. But...
I can't seem to get it working with a MySQL database. I have the Fluent Nhibernate example project running fine with the SQLite database (Fluent NHibernate: Getting Started), but as soon as I change the database configuration to this:
return Fluently.Configure()
.Database(MySQLConfiguration.Standard.ConnectionString(
x => x.Database("database")
.Server("server")
.Username("login")
.Password("password")
)
)
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<Program>())
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
I get a strange exception:
Value cannot be null. Parameter name: stream
I know that I can connect to the MySQL with a simple SQL statement from the same project.
Any ideas? :)
Unfortunatly I canĀ“t tell you why but it seems to be an issue with the MySql connector.
Add this:
.ExposeConfiguration(c => c.Properties.Add("hbm2ddl.keywords", "none"));
to your configuration and see if it helps. I found the solution at the hibernate forums.
Does your schema exist? Because your using .ExposeConfiguration(BuildSchema) to "build" it?
I had the same problem and finally I figured it out.
First you need to set a database with the tables used in the example. See script below. (I omitted the Location object).
Then I used the following CreateSessionFactory code:
var cfg = MySQLConfiguration
.Standard
.ShowSql()
.UseOuterJoin()
.ConnectionString("Server=localhost;Port=3306;Database=testdb;Uid=USER;Password=PASSWORD;use procedure bodies=false;charset=utf8")
.Driver<NHibernate.Driver.MySqlDataDriver>()
;
return Fluently.Configure()
.Database(cfg)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Program>())
.BuildSessionFactory()
;
Create BD and table script:
DROP DATABASE IF EXISTS testdb;
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE Employee
(
id int not null primary key auto_increment,
FirstName TEXT,
LastName TEXT,
Store_id int(10)
);
CREATE TABLE Product
(
id int not null primary key auto_increment,
Name TEXT,
Price DOUBLE
);
CREATE TABLE Store
(
id int not null primary key auto_increment,
Name TEXT
);
CREATE TABLE StoreProduct
(
Store_id int(10) DEFAULT '0' NOT NULL,
Product_id int(10) DEFAULT '0' not null,
PRIMARY KEY (Store_id, Product_id)
);
SELECT 'Employee table' as '';
desc Employee;
SELECT 'Product table' as '';
desc Product;
SELECT 'Store table' as '';
desc Store;
SELECT 'shopgroup_member table' as '';
desc StoreProduct;
Related
I have a SQL table that has two foreign keys and when I run Entity Data Model Wizard and select Code First from database, and then create the tables, my table won't show up as a class. It generates something in the primary model class that looks like this:
modelBuilder.Entity<User>()
.HasMany(e => e.Categories)
.WithMany(e => e.Users)
.Map(m => m.ToTable("UserCategory").MapLeftKey("UserID").MapRightKey("ID"));
But I don't know how to use that to add or delete from that table, since it won't show up as a class when I'm coding.
My tables are:
CREATE TABLE [User]
(
ID NVARCHAR(128) PRIMARY KEY,
FirstName VARCHAR(255) NOT NULL,
LastName VARCHAR(255),
JoinDate DATETIME,
ZipCode VARCHAR(25),
SearchRadius INT,
LoginToBusinessSide BIT
);
/*The categories businesses can fall under. */
CREATE TABLE Category
(
ID INT IDENTITY(1,1) PRIMARY KEY,
[Name] VARCHAR(255) UNIQUE NOT NULL,
);
/*The categories chosen by a specific user to get notified of*/
CREATE TABLE UserCategory
(
ID INT FOREIGN KEY REFERENCES Category(ID),
UserID NVARCHAR(128) FOREIGN KEY REFERENCES [User](ID),
CONSTRAINT PK_UserCategory PRIMARY KEY (ID, UserID)
);
How do I get UserCategory to show up as its own class, so I can easily access it?
I want to be able to just access it like every other class:
db.UserCategories.ID =
How can I
ADO doesn't create a class for my many to many table, but I can still access it. To add new categories to it, I use this code:
for(var i = 0; i < categories.Length; ++i)
{
var user = db.Users.Find(thisUser.ID);
var cat = db.Categories.Find(categories[i]);
user.Categories.Add(cat);
}
I have to an active connection to both tables that the foreign keys are linked to, and then when I add one to the Categories table, it goes to the correct place.
If you understand exactly why this works, or if there's a better way, please do comment.
I am experimenting with Dapper for the first time. I have two tables: Films and Ratings.
CREATE TABLE [dbo].[Films]
(
[Id] INT NOT NULL PRIMARY KEY,
[Title] VARCHAR(250) NOT NULL,
[Genre] VARCHAR(50) NOT NULL,
[RatingId] INT NOT NULL,
CONSTRAINT [FK_Films_To_Ratings] FOREIGN KEY (RatingId) REFERENCES Ratings(Id)
)
CREATE TABLE [dbo].[Ratings]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] VARCHAR(50) NOT NULL
)
I have written a stored procedure that will return all films in the Films table and joins with the Ratings table. Dapper works easily when I have the table structured using the same name between the FK and PK of the tables.
CREATE PROCEDURE [dbo].[GetFilms]
AS
BEGIN
SELECT
F.Id,
F.Title,
F.Genre,
F.RatingId,
R.Name
FROM
dbo.Films as F
INNER JOIN
dbo.Ratings as R
ON
F.RatingId = R.Id;
END
When my query runs, the film object becomes instantiated correctly but the RatingId was set to 0 (since int defaults to 0). The rating property contains the name, but the Id was also set to 0.
return this._db.Query<Film, Rating, Film>(
"dbo.GetFilms",
(f, r) =>
{
f.Rating = r;
return f;
},
splitOn: "RatingId",
commandType: CommandType.StoredProcedure
).ToList();
How can I successfully run my Dapper query and get the exact results I need when the column names are not identical like in my example? Table structure looks cleaner to me when I have columns named Ratings.Id instead of Ratings.RatingId.
Dapper will try and map property for property at the point you start splitting. You want your query to look like the following, and you can ditch the splitOn since you are splitting on Id.:
SELECT
F.Id,
F.Title,
F.Genre,
--Rating object starts here
R.Id,
R.Name
FROM
dbo.Films as F
INNER JOIN
dbo.Ratings as R
ON
F.RatingId = R.Id;
I'm using WPF MVVM Pettern and
I Have a simple table on SQL Server 2012 which its ID(key) column is computed in an StoredProcedure, called PersonInsert: (This is simplified, but what is computed is more complex than this, anyway it's an int at last)
USE [Guard]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[PersonInsert]
#FName NVARCHAR(50) ,
#LName NVARCHAR(50) ,
#ID INT = NULL OUTPUT
AS
BEGIN
BEGIN TRY
SELECT #ID = ISNULL(MAX(ID), 0) + 1
FROM dbo.Person
INSERT INTO [dbo].[Person]
( [ID] ,
[FName] ,
[LName]
)
VALUES ( #ID ,
#FName ,
#LName
)
END TRY
BEGIN CATCH
DECLARE #ErrMsg NVARCHAR(MAX) ,
#ErrSvr INT ,
#ErrStt INT
SELECT #ErrMsg = ERROR_MESSAGE() + '|' + ERROR_PROCEDURE() + '|'
+ CAST(ERROR_LINE() AS NVARCHAR(5)) ,
#ErrSvr = ERROR_SEVERITY() ,
#ErrStt = ERROR_STATE()
RAISERROR (#ErrMsg, #ErrSvr, #ErrStt)
END CATCH
END
GO
In the .net side, I use EF 6.1 Code-First to handle data and mapped to SPs so I have OnModelCreating like this:
modelBuilder.Entity(Of Person)().MapToStoredProcedures(
Sub(x)
x.Insert(Function(e) e.HasName("[dbo].[PersonInsert]"))
x.Update(Function(e) e.HasName("[dbo].[PersonUpdate]"))
x.Delete(Function(e) e.HasName("[dbo].[PersonDelete]"))
End Sub)
And My Model is:
<Table("Person")> _
Partial Public Class Person
<DatabaseGenerated(DatabaseGeneratedOption.None), Key> _
Public Property ID As Integer
Public Property FName As String
Public Property LName as String
End Class
Now the strange thing is, when I try to Insert Data (Adding New Person) at first time, the db.SaveChanged() works great, but for second time it throws InvalidOperation exception with a message:
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: Saving or accepting changes failed because more than one entity of type 'Shoniz.Guard.WPFGuardApplication.Person' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.
He is right! the data is comitted successfully! and I'm right too, because my ID(key) column is computed right and it's completely unique. Either I have used the DatabaseGeneratedAttribute with none value on ID, but the result is the same :(
Even when I re-query the db to check about duplicate keys, I find NOTHING!
Why this exception is thrown?
How can I prevent that?
Is there anyway to Ignore the changes after db.SaveChanges()?
First of all change DatabaseGeneratedOption.None to DatabaseGeneratedOption.Indetity
and finally change stored procedure to this:
BEGIN TRY
SELECT #ID = ISNULL(MAX(ID), 0) + 1
FROM dbo.Person
INSERT INTO [dbo].[Person]
( [ID] ,
[FName] ,
[LName]
)
VALUES ( #ID ,
#FName ,
#LName
)
--You have to tell EF this is returned Id of inserted person
SELECT #ID as ID
END TRY
I'm using EF4 with Visual Studio 2010 and SQL Server 2008 R2.
I am selecting an entity. After that I call a stored procedure which updates that entity en reselects it from the database. When I catch the result of the stored procedure in code, I see that the old (previously selected) properties.
Obviously I'm looking at the cached entity value. Is there a way to signal EF that my entity was updated? Or a magic property of some sort?
My database table (and entity) look something like this:
CREATE TABLE [Message]
(
ID int IDENTITY(1, 1) PRIMARY KEY,
Content XML,
StateID int NOT NULL,
)
My SP is something like this:
CREATE PROCEDURE sp_Queue_s
AS
BEGIN
DECLARE #queue table ([ID] int NOT NULL)
BEGIN TRAN
INSERT INTO #queue
SELECT [ID]
FROM [Message]
WHERE StateID = 1
UPDATE [Message]
SET StateID = 2
WHERE ID IN (SELECT ID FROM #queue)
COMMIT TRAN
-- Select the queue
SELECT [ID], [Content], [Message]
FROM [Message]
WHERE [ID] IN (SELECT ID FROM #queue)
END
My C# code looks something like this:
using (var context = new MyEntities())
{
int id = 1;
var message = context.Messages.Single(m => m.ID == id);
var messages = context.GetQueue(); // Function import of sp_Queue_s, maps on the Message entity
var messageUpdated = messages.Single(m => m.ID == id);
}
GetQueue should be a generated method internally calling context.ExecuteFunction. ExecuteFunction has multiple overloads and one of them accepts MergeOption. Try to call ExecuteFunction directly with MergeOption.OverwriteChanges.
I am particularly confused by the following test case:
public void TestMapping()
{
var autoPersistenceModel = AutoMap.AssemblyOf<RepositoryEntity>().Where(
x => x.Namespace.EndsWith("Descriptors"));
var configuration = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.ShowSql().InMemory)
.Mappings(x => x.AutoMappings.Add(autoPersistenceModel))
.ExposeConfiguration(x => new NHibernate.Tool.hbm2ddl.SchemaExport(x).Create(true, false));
var sessionFactory = configuration.BuildSessionFactory();
using (var session = sessionFactory.OpenSession())
{
new PersistenceSpecification<IndicatorUnitDescriptor>(session)
.CheckProperty(x => x.Name, "Name1")
.CheckProperty(x => x.Timestamp, new DateTime(2000, 10, 10))
.VerifyTheMappings();
}
}
As you can see, I'm experimenting with automappings, but unfortunately the following test case raises the following SQLite exception (the first contains the actual queries done):
drop table if exists "IndicatorUnitDescriptor"
drop table if exists "StockUnitDescriptor"
create table "IndicatorUnitDescriptor" (
Id integer,
Name TEXT,
Timestamp DATETIME,
primary key (Id)
)
create table "StockUnitDescriptor" (
Id integer,
Name TEXT,
Timestamp DATETIME,
primary key (Id)
)
NHibernate: INSERT INTO "IndicatorUnitDescriptor" (Name, Timestamp) VALUES (#p0, #p1); select last_insert_rowid();#p0 = 'Name1' [Type: String (0)], #p1 = 10.10.2000 0:00:00 [Type: DateTime (0)]
System.Data.SQLite.SQLiteException: SQLite error
no such table: IndicatorUnitDescriptor
And I can't understand why does it happen this way - the SQL commands seem to be working appropriately and the corresponding table should be created by the create table query.
I assume something is wrong in my code (I probably missed something). Could you help me?
I think your using two sessions. One during database creation and in your test proper. Try setting up like this.
Configuration cfg = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory())
.Mappings(m => m.HbmMappings.AddFromAssembly(_mappingsAssembly))
.BuildConfiguration();
var session = cfg.BuildSessionFactory().OpenSession();
new SchemaExport(cfg).Execute(false, true, false, session.Connection, null);