Non-unique columns in NHibernate query - nhibernate

I have the following case:
In SqlServer database there are two tables defined like this:
CREATE TABLE [dbo].[T1](
[c1] [nvarchar](50) NOT NULL,
[c2] [int] NULL,
CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED ([c1] ASC)) ON [PRIMARY]
CREATE TABLE [dbo].[T2](
[c1] [nvarchar](50) NOT NULL,
[c2] [int] NULL,
CONSTRAINT [PK_T2] PRIMARY KEY CLUSTERED ([c1] ASC)) ON [PRIMARY]
I add one record to T1 and another one to T2, like this:
INSERT INTO [dbo].[T1] ([C1],[C2]) VALUES ('a', 1)
INSERT INTO [dbo].[T2] ([C1],[C2]) VALUES ('a', 2)
Then I execute the following C# code (where Session is a NHibernate session):
var data = Session.CreateSQLQuery("SELECT * FROM T1 JOIN T2 ON T1.C1 = T2.C1").List();
In "data" I receive one record with four columns. Values are the following:
"a", 1, "a", 1.
If I execute the query manually in Sql Server Management Studio I get good results "a", 1, "a", 2. For some reason NHibernate is not able to distinguish columns which have the same name or alias.
Does anyone know how if there is a way to make this work? I cannot guarantee using unique aliases instead of *, I also need to use a raw query instead of object mapping. Currently my only workaround is to use a good old data set, without NHibernate. I will be most grateful for all suggestions and help :)

If your table was mapped to a class, and you just wanted all ("*") mapped properties, you could
var data = Session.CreateSQLQuery("SELECT {T1.*},{T2.*} FROM T1 JOIN T2 ON T1.C1 = T2.C1")
.AddEntity("T1", typeof(TheClass))
.AddEntity("T2", typeof(TheClass))
.List();
If not, I think your best bet is to use "good old data set" or a datareader, but you could expose it is an extension method on ISession, to make connection management etc. transparent.

Related

Insert only modified values and column names into a table

I have a sql server 2012 database. In which i have a changeLog table that contains
TableName, ColumnName, FromValue and ToValue columns. Which will be used to keep track of modified columns and data.
So if any update occur through application then only modified columns should insert into this table with its new and old value.
Can anyone help me in this.
For Example:
If the procedure updates all columns of property table (propertyName, address)
then if user update propertyName (but update also contains address column but with no data change) then only propertyName and its data will be inserted into ChangeLog table not address column and its data because address data does not contains any data change.
IF there is no other auditing requirement at all - you would not be thinking about Auditing in any way without this - then OK, go for it. However this is a very limited use of Auditing: User X changed this field at time Y. Generally this is interesting as part of a wider question: what did user X do? What happened to that customer data in the database to end up the way it is now?
Questions like that are harder to answer if you have the data structure you propose and would be quite onerous to reconstruct. My usual approach would be as follows. Starting from a base table like so (this from one of my current projects):
CREATE TABLE [de].[Generation](
[Id] [int] IDENTITY(1,1) NOT NULL,
[LocalTime] [datetime] NOT NULL,
[EntityId] [int] NOT NULL,
[Generation] [decimal](18, 4) NOT NULL,
[UpdatedAt] [datetime] NOT NULL CONSTRAINT [DF_Generation_UpdatedAt] DEFAULT (getdate()),
CONSTRAINT [PK_Generation] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
(I've excluded FK definitions as they aren't relevant here.)
First create an Audit table for this table:
CREATE TABLE [de].[GenerationAudit](
[AuditId] int identity(1, 1) not null,
[Id] [int] NOT NULL,
[LocalTimeOld] [datetime] NULL,
[EntityIdOld] [int] NULL,
[GenerationOld] [decimal](18, 4) null,
[UpdatedAtOld] [datetime] null,
[LocalTimeNew] [datetime] null,
[EntityIdNew] [int] null,
[GenerationNew] [decimal](18, 4) null,
[UpdatedAtNew] [datetime] NOT NULL CONSTRAINT [DF_GenerationAudit_UpdatedAt] DEFAULT (getdate()),
[UpdatedBy] varchar(60) not null
CONSTRAINT [PK_GenerationAudit] PRIMARY KEY CLUSTERED
(
[AuditId] ASC
)
This table has an *Old and a *New version of each column that can't change. The Id, being an IDENTITY PK, can't change so no need for an old/new. I've also added an UpdatedBy column. It also has a new AuditId IDENTITY PK.
Next create three triggers on the base table: one for INSERT, one for UPDATE and one for DELETE. In the Insert trigger, insert a row into the Audit table with the New columns selected from the inserted table and the Old values as null. In the UPDATE one, the Oldvalues come from the deleted and the new from the inserted. In the DELETE trigger, old from from deleted and the new are all null.
The UPDATE trigger would look like this:
CREATE TRIGGER GenerationAuditUpdate
ON de.Generation
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
insert into de.GenerationAudit (Id, LocalTimeOld, EntityIdOld, GenerationOld, UpdatedAtOld,
LocalTimeNew, EntityIdNew, GenerationNew, UpdatedAtNew,
UpdatedBy)
select isnull(i.Id, d.Id), d.LocalTime, d.EntityId, d.Generation, d.UpdatedAt,
i.LocalTime, i.EntityId, d.Generation, getdate(),
SYSTEM_USER)
from inserted i
full outer join deleted d on d.Id = i.Id;
END
GO
You then have a full before/after picture of each change (and it'll be faster than seperating out diffs column by column). You can create views over the Audit table to get entries where the Old value is different to the new, and include the base table Id (which you will also need in your structures!), the user who did it, and the time they did it (UpdatedAtNew).
That's my version of Auditing and it's mine!

Inner join between different database

I want to create a table using the following script in a database called DeltaDatabase:
CREATE TABLE [dbo].[OutStatus](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[OutId] [int] NOT NULL,
[StatusType] [varchar](255) NULL,
[StatusDate] [datetime] NULL)
I would then like to INNER JOIN a column into this table from another database called CoreDatabase.
The column name is sourceId from the table Client. So in other words OutId needs to be foreign key of SourceId.
How do I join that column into my OutStatus table from the other database using the create table script?
The basic syntax to retrieve data would be:
SELECT *
FROM CoreDatabase.dbo.Client c
INNER JOIN DeltaDatabase.dbo.OutStatus os ON c.SourceId = os.OutId
You need to fully qualify the tables name with: DatabaseName.Schema.TableName
You may wish to limit the columns or add a where clause to reduce the data that is returned.
As far as creating a foreign key across databases goes, it's not something you can do. You would have to use triggers or some other logic to maintain referential integrity between the primary and foreign keys.
Try the below query
Select * from DeltaDatabase.dbo.OutStatus OUS
Inner Join CoreDatabase.dbo.Client CL on OUS.OutId=CL.sourceId

Triggering a timestamp update

For every INSERT, how do I populate my DateStamp field with the current datetime?
I've created an error output table for my SSIS task:
Here's the table:
CREATE TABLE [dbo].[gbs_CRMErrorOutput](
[ID] [uniqueidentifier] NULL,
[ErrorCode] [nvarchar](50) NULL,
[ErrorColumn] [nvarchar](500) NULL,
[CrmErrorMessage] [nvarchar](max) NULL,
[targetid] [uniqueidentifier] NULL,
[subordinateid] [uniqueidentifier] NULL,
[DateStamp] [datetime] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Please note that I do not have an auto-increment or any key in the table.
I'm also wondering what would be a best practice for this?
Here is an example of using not null with a default. In your real table you may want to name your default constraint. If you define the constraint inline like this it will still be named but it will be automatically assigned.
CREATE TABLE #MyTable
(
MyID INT IDENTITY NOT NULL,
SomeValue VARCHAR(10),
DateCreated DATETIME NOT NULL DEFAULT GETDATE()
)
INSERT #MyTable(SomeValue)
VALUES ('Value1')
--This next line just waits for 1 second.
--This will demonstrate multiple inserts at different times so you can the values change
WAITFOR DELAY '00:0:01'
INSERT #MyTable(SomeValue)
VALUES ('Value2')
SELECT *
FROM #MyTable
DROP TABLE #MyTable
Two good options:
1) Create a DEFAULT CONSTRAINT on your table with GETDATE() specified for your column (good example here). Within SSIS, do not map any value to that column - leave it as Ignore. Make sure that Keep Nulls is not checked. Note that you might have to fiddle with the settings of your OLE DB Destination - uncheck Identity Insert if there's a problem. I've also seen cases where the column had to allow NULLs - that only affects certain scenarios.
2) Add a Derived Column transformation to your data flow, setting it up to add a new column to the flow. I usually use the System::StartTime variable here, so that all records inserted during a single ETL run will share the same inserted date, but you could just as easily use the SSIS function GETDATE().
Map the new column you just created to your OLE DB Destination.

Table cell to count rows in other table

I'm not entirely sure if I'm even going about this in the right manner.
MVC+EF site so i could do this in the controller but I would prefer it in the DB if possible.
I have two tables. One contains entries and one contains a list of members. I want the list of members to have a column that contains the count of how many times the member name appears in the list of entries. Can I do this in the definition of the table itself?
I know this query works:
select count(*)
from dbo.Entries
where dbo.Entries.AssignedTo = 'Bob Smith'
But is there any way of doing this? What is the correct syntax?
CREATE TABLE [dbo].[Members] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Email] NVARCHAR (500) NOT NULL,
[Count] INT = select count(*) from dbo.Entries where dbo.Entries.AssignedTo = [Name]
PRIMARY KEY CLUSTERED ([ID] ASC)
I've done some searching and have tried a few different syntax's but I'm completely lost at this point so if anyone can get me headed in the correct direction I would really appreciate it.
Thanks in advance.
You could create Members as a view combining both the Entries data and another table. (Warning: Syntax not tested)
CREATE TABLE [_member_data] (
[ID] INT IDENTITY(1, 1) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Email] NVARCHAR (500) NOT NULL,
PRIMARY KEY CLUSTERED ([ID] ASC)
);
CREATE VIEW [dbo].[Members] AS
SELECT ID, Name, Email, COUNT(*)
FROM _member_data JOIN dbo.Entries ON [Name] = [AssignedTo]
GROUP BY 1, 2, 3;
It is possible to take this even further with triggers/rules that rewrite attempted inserts into Members as inserts to the appropriate backing table. But to get the kind of expressive information that you are looking for, you really want to explore using a view.

How to update 2nd table with identity value of inserted rows into 1st table

I have the following table structures
CREATE TABLE [dbo].[WorkItem](
[WorkItemId] [int] IDENTITY(1,1) NOT NULL,
[WorkItemTypeId] [int] NOT NULL,
[ActionDate] [datetime] NOT NULL,
[WorkItemStatusId] [int] NOT NULL,
[ClosedDate] [datetime] NULL,
)
CREATE TABLE [dbo].[RequirementWorkItem](
[WorkItemId] [int] NOT NULL,
[RequirementId] [int] NOT NULL,
)
CREATE TABLE #RequirmentWorkItems
(
RequirementId int,
WorkItemTypeId int,
WorkItemStatusId int,
ActionDate datetime
)
I use the #RequirmentWorkItems table to create workitems for requirements. I then need to INSERT the workitems into the WorkItem table and use the identity values from the WorkItem table to create the cross-reference rows in the RequirementWorkItem table.
Is there a way to do this without cursoring thru each row? And I can't put the RequirementId into the WorkItem table because depending on the WorkItemTypeId the WorkItem could be linked to a Requirement or a Notice or an Event.
So there are really 3 xref tables for WorkItems. Or would it be better to put a RequirementId, NoticeId and EventId in the WorkItem table and 1 of the columns would have a value and other 2 would be null? Hopefully all this makes sense. Thanks.
You should read MERGE and OUTPUT – the swiss army knife of T-SQL for more information about this.
Today I stumbled upon a different use for it, returning values using an OUTPUT clause from a table used as the source of data for an insertion. In other words, if I’m inserting from [tableA] into [tableB] then I may want some values from [tableA] after the fact, particularly if [tableB] has an identity. Observe my first attempt using a straight insertion where I am trying to get a field from #source.[id] that is not used in the insertion: