C# - Nhibernate question - c#

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

Related

EF Lambda for SQL : How to get a new column based on some string presence in other column of the same table

I want SQL query equivalent in EF Core Lambda, to get an extra column as either true or false, based on some substring(in this case DEALER) if present in other column's data of the same table.
myTable
Id col1
1 I have substring - DEALER
2 I do not have any substring
I need the output as
Id, IsDealer
1, true
2, false
I tried the following SQL query,
SELECT [Id] ,
CASE WHEN [col1] LIKE '%DEALER%' THEN 'true' ELSE 'false' END as IsDealer
FROM [dbo].[myTable]
I get proper output, But what is the above SQL query EF CORE equivalent ?
I tried
_Context.myTable.Where(et => et)
.Select(s => new myTableEFCoreModel
{
Id = s.Id,
**<what goes here for IsDealer>**
});
You're returning the string in col1 so just doing a string compare should be all you need:
_Context.myTable.Where(et => et)
.Select(s => new myTableEFCoreModel
{
/* same as select [Id] in sql query */
Id = s.Id,
/* same as case when [col1] like "%DEALER%" then 'true' else 'false' as IsDealer */
IsDealer = s.col1.Contains("DEALER")
});
You can have something like IsDealer = s.col1.Contains("TextYouWantToSearch")

How to cache .Count() queries in NHibernate.Linq?

How do I cache the result of such a query:
Session.Query<Entity>().Count(e=> e.Property == someConstant)
I cannot place Cacheable() after it, and if I place it before the Count(), it would fetch the entire result set, wouldnt it?
Adding Cacheable before the count will cause the aggregate count results to be cached. This can be seen by the SQL generated from my example below.
Domain and Mapping Code
public class Entity
{
public virtual long id { get; set; }
public virtual string name { get; set; }
}
public class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
Id(x => x.id).GeneratedBy.Identity();
Map(x => x.name);
Cache.ReadOnly();
}
}
The test code itself.
using (var session = NHibernateHelper.OpenSession())
using (var tx = session.BeginTransaction())
{
session.Save(new Entity() { name = "Smith" });
session.Save(new Entity() { name = "Smithers" });
session.Save(new Entity() { name = "Smithery" });
session.Save(new Entity() { name = "Smith" });
tx.Commit();
}
String name_constant = "Smith";
using (var session = NHibernateHelper.OpenSession())
using (var tx = session.BeginTransaction())
{
var result = session.Query<Entity>().Cacheable().Count(e => e.name == name_constant);
}
using (var session = NHibernateHelper.OpenSession())
using (var tx = session.BeginTransaction())
{
var result = session.Query<Entity>().Cacheable().Count(e => e.name == name_constant);
}
The SQL generated from the above code can be seen below. As you can see, there are four INSERT statements, one for each session.Save. Whereas there is only one SELECT despite the two queries, each performing under a separate session. This is because the result of the count has been cached by NHibernate.
NHibernate: INSERT INTO [Entity] (name) VALUES (#p0); select SCOPE_IDENTITY();
#p0 = 'Smith' [Type: String (4000)]
NHibernate: INSERT INTO [Entity] (name) VALUES (#p0); select SCOPE_IDENTITY();
#p0 = 'Smithers' [Type: String (4000)]
NHibernate: INSERT INTO [Entity] (name) VALUES (#p0); select SCOPE_IDENTITY();
#p0 = 'Smithery' [Type: String (4000)]
NHibernate: INSERT INTO [Entity] (name) VALUES (#p0); select SCOPE_IDENTITY();
#p0 = 'Smith' [Type: String (4000)]
NHibernate: select cast(count(*) as INT) as col_0_0_ from [Entity] entity0_
where entity0_.name=#p0;
#p0 = 'Smith' [Type: String (4000)]
The possible scenarios which will cause NHibernate to ignore Cacheable and go back to the DB are when:
The second level cache is not enabled in the session factory configuration.
The entity has not been marked as cacheable.
The only other scenario I know of that will cause NHibernate to perform two SELECT queries is when the entity has been evicted from the cache, either explicitly using sessionFactory.Evict or by the cached entity becoming expired between the two calls.

Testing NHibernate Map

What's the best way to test your NHibernate Mapping classes?
Let's assume I want to test the following map:
public QuoteMap()
{
this.Table("QUOTE");
this.Id(x => x.Id).Column("QUOTE_ID").GeneratedBy.Sequence("SEQ_QUOTE_ID");
this.Map(x => x.IsDeleted).Column("IS_DELETED");
this.References(x => x.Proposal).Column("PROPOSAL_ID");
}
where Proposal type is mapped to another table.
QUOTE table looks like this:
CREATE TABLE "QUOTE"
(
"QUOTE_ID" NUMBER(18,0) NOT NULL,
"PROPOSAL_ID" NUMBER(18,0) NOT NULL ENABLE,
"IS_DELETED" NUMBER(1,0) DEFAULT 0 NOT NULL ENABLE,
CONSTRAINT "PK_QUOTE" PRIMARY KEY ("QUOTE_ID"),
CONSTRAINT "FK_QUOTE_PROPOSAL" FOREIGN KEY ("PROPOSAL_ID") REFERENCES
"PROPOSAL" ("PROPOSAL_ID") ENABLE
)
Option1: PersistenceSpecification
new PersistenceSpecification<Quote>(session, new CustomEqualityComparer())
.CheckProperty(c => c.TenantId, 1)
.CheckProperty(c => c.IsDeleted, false)
.CheckReference(
c => c.Proposal,
new Proposal
{
Id = 1,
IsDeleted = false,
TenantId = 1,
VersionNumber = 1,
OutletId = 1,
StatusId = "TST"
})
.VerifyTheMappings();
transaction.Commit();
...this test would fail with the following exception:
NHibernate.Exceptions.GenericADOException: could not insert:
[Quote#18][SQL: INSERT
INTO QUOTE (IS_DELETED, PROPOSAL_ID, QUOTE_ID)
VALUES (?, ?, ?)] ---> Oracle.DataAccess.Client.OracleException:
ORA-02291: integrity constraint (PROPOSALOWN.FK_QUOTE_PROPOSAL)
violated - parent key not found
...because it has a dependency on the PROPOSAL record with Id = 1 being there.
Another problem with this is if you have coincidently mapped PropertyA to ColumnB and PropertyB to ColumnA your test would pass and won't point out your mistake.
Option2: Raw SQL to INSERT, NHibernate to SELECT
Now this would be ideal: you insert by issuing a raw SQL statement e.g.
INSERT INTO QUOTE (QUOTE_ID, PROPOSAL_ID, IS_DELETED)
SELECT SEQ_QUOTE_ID.NextVal, 1, 0 from dual;
Then you read using Nhibernate and check the values.
The problem is, again, dependency on PROPOSAL record being there. Insert PROPOSAL record for this test? Sure! However, Proposal table has another set of FOREIGN KEYS, so you may end up inserting ROWS into dozens of tables just to test your mapping... no likey!
Surely there's a much better, simpler way to test NHibernate Maps. Could you suggest one?
You should be using CheckReference for the proposal:
.CheckReference(
c => c.Proposal,
new Proposal
{
IsDeleted = false,
TenantId = 1,
VersionNumber = 1,
OutletId = 1,
StatusId = "TST"
})

Entity Framework: Entity is cached when update and reselecting it in a stored procedure using a function import

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.

Fluent Nhibernate: Can't create database connection to MySQL

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;

Categories

Resources