Özgür Özvarış

Bir yazılımcının kırık dökük dünyası

Msql foreign key arka planı

clock Haziran 28, 2016 17:11 by author OzgurOzvaris

Merhaba ,

Bu günki yazımızda mssql de foreign key ile ilgili bir kaç script paylayacağım. Öncelikle bu konu nerden çıktı diye düşünebilirsiniz çıkış noktası entityframework (EF) te (Database First) alter table ile değişiklik yapılan bir tablonun EF foreign key (FK) bağlantıları uçtu. Neden uçtuğunu anlamak için EF kün tablo eklerken kullandığı sql cümlelerini  profiler aracalığı ile  incelemek ve süzerek boş dönen sql cümlesini tespit etmek durumuda kaldım. Baştan söyleyim çok zor bir yöntem oldu ancak sonuçta sorunu bulmamı sağladı.

Baştan başlar isek öncelilkle birbiri ile foreign key bağlantısı kuracağımız iki tablo açalım

CREATE TABLE Table_Ttmp 

(
Table_T_ID numeric(12, 0) IDENTITY(1,1),
PRIMARY KEY (Table_T_ID),


)

CREATE TABLE Table_Mtmp 

(
Table_M_ID numeric(12, 0) IDENTITY(1,1),
Table_T_ID numeric(12, 0) NOT NULL,
PRIMARY KEY (Table_M_ID),
--FOREIGN KEY (Table_T_ID) REFERENCES Table_Ttmp ,  

)

Bir foreign key constraint eklemek için standart sql cümlesini çalıştırarak devam edelim. (Yukarıdaki scriptte aslında FK oluşturma ile ilgili satır commentli. Bu satırıda aynı işlemi yapar.)

ALTER TABLE dbo.Table_Mtmp ADD CONSTRAINT
FK_Table_Mtmp_Table_Ttmp FOREIGN KEY
(
Table_M_ID
) REFERENCES dbo.Table_Ttmp
(
Table_T_ID
) ON UPDATE  NO ACTION 
 ON DELETE  NO ACTION

Üçüncü bir FK oluşturma yöntemide Sql Server Management Studio (SQLMS) aracılığı ile tabloda design diyerek ve Relations ları seçerek FK oluşturmak. Burada kaydet demeden oluşturulan scripte bakarsanız yukarıda ki scriptin aynısını oluşturduğunu görecektsiniz

Yukarıdaki üç yöntemden herhabgi biri  ile FK ilişkilsi eklediğinizde MSSQL iki tablo arasında ilişki kuruyor. Yukarıdaki tabloda anlaşıldığı üzere ilişki Table_Mtmp ile Table_Ttmp arasıdına oluşturulmuş durumda. Table_Ttmp Primary key'in olduğu tablo, Table_Mtmp foreign key'in olduğu tablo.

Buraya kadar anlattıklarımız giriş şimdi öğreneceklerimizin alt yapısını oluşturmak içinde. SQLMS ekranlarıyla geldiğimiz aşamayı görelim. 

 

 

Şimdi asıl paylaşacağım aşamalara geldik.

 

SQLMS yukarıdaki bağlantıyı göstebilmek için şimdi paylaştığım sql cümlesini kullanıyor. Bu scriptin düzgün sonuç vermesi için use ile db niniz seçmeniz gerekiyor...

select Fk.name, Fk.object_id, Fk.is_disabled, Fk.is_not_for_replication, Fk.delete_referential_action, Fk.update_referential_action, 
object_name(Fk.parent_object_id) as Fk_table_name, schema_name(Fk.schema_id) as Fk_table_schema, TbR.name as Pk_table_name, 
schema_name(TbR.schema_id) Pk_table_schema, col_name(Fk.parent_object_id, Fk_Cl.parent_column_id) as Fk_col_name, 
col_name(Fk.referenced_object_id, Fk_Cl.referenced_column_id) as Pk_col_name, Fk_Cl.constraint_column_id, Fk.is_not_trusted 
from sys.foreign_keys Fk 
left outer join sys.tables TbR on TbR.object_id = Fk.referenced_object_id 
inner join sys.foreign_key_columns Fk_Cl on Fk_Cl.constraint_object_id = Fk.object_id 

where	Fk.parent_object_id = object_id(N'dbo.Table_Mtmp') or Fk.referenced_object_id = object_id(N'dbo.Table_Mtmp')

 

EF ise bu ilişkiyi almak için başka bir sql script kullanıyor. EF Update Database Model dediğinizde ve yeni bir tablo eklemek istediğinizde yada bir tablodaki güncellemeyi almak için silip tekrar eklediğinizde uzunca birkaç sql cümlesi gönderiyor. Bunlardan birtanesi tablolar arasındaki ilişkiyi çekmek için. 359 satırlık bir sql cümlesi olduğu için onu dosya olarak paylaşıyorum. Bunu paylaşma nedenim bir kaynak olması için. Yoksa satır satır bu sql'in ne yaptığını bende bilmiyorum. Ancak biraz sonra açıklayacağım scriptler bu büyük scriptin içinden işlevselliklerine göre seçilerek elde edildi. 

 EFFullScript.txt (16,72 kb)

 

Bu uzunça scriptin çıktısı yukarıda paylaştığım ekran. Burda belirtilen bilgiler Table_Ttmp diye bir tablonun Table_T_ID primary key alnı ile Table_Mtmp tablosunun Table_M_ID ( Doğru bağlantı tabiki Table_T_ID olması gerekiyordu ama test tablosu olduğu için düzeltmedim) kolonu arasında FK_Table_Mtmp2_Table_T isimli (yukarıda SQLMS da aynı isim var)  [dbo][FK_Table_Mtmp2_Table_T] id li (Bu id name'in DB tarafındaki karşılığı) bir ilişki vardır. Bu satır boş gelirse EF association Model de FK ilişkiyi kuramıyor. Bizde de aynen böyle oldu ve FK SQLMS da gözüktüğü halde EF de gözükmüyordu. Bu nedenle sorunu bulmak için bu uzunca scripti incelemeye almak durumunda kaldık. Buda bizi SQL server FK mantığının derinlerine doğru bir yolculuğa çıkardı. Merak eden buradan sonraki aşamayı takip ederek bu derinliğe bizle birlikte gelebilir.

Öncelikle kısaca fikir edinmek için bu uzun sql cümlesinden birkaç kelime edeyim. Bu sql cümlesinin aslında ilk 358 satırı sabit 359. satır yani "WHERE" ile başlayan satır modelinizdeki tablolara göre dinamik olarak tablo filitreleri oluşturuyor. Kodun daha iyi anlaşılabilmesi için 359. satırdan parametre satırını 360'a valularınıda 361'i satırdan itibaren tablo lara göre enterlı olarak yazdım. Şimdi 361. satırı paylaşıyorum.

@p0=N'K14_abc',@p1=N'dbo',@p2=N'Table_Mtmp',
@p3=N'K14_abc',@p4=N'dbo',@p5=N'Table_Ttmp',
@p6=N'K14_abc',@p7=N'dbo',@p8=N'Table_Mtmp',
@p9=N'K14_abc',@p10=N'dbo',@p11=N'Table_Ttmp'

Görüldüğü gibi burada modele eklediğim başta oluşturduğumuz  Table_Mtmp ve Table_Ttmp satırlarımıza ait tekrar etmiş 4 satır mevcut. Eğer buraya bir 3. tablo daha ekleseydik 360. satırdaki where bölümüne ve parametre value bölümüne bu tablolarda eklenmiş olacaktı ancak ana sql cümlesi değişmeyecekti.  Şimdi gelelim bizim tablolarımızdaki ilişkileri alan sql parçasına. Bu aşamadan sonra paylaşacağım sql scriptler bu 359 satırlık bölümden olacak.

Öncelikle iki tablo arasında FK yı ve FK ilişkisinin temel bilgilerini gösteren ve bu ilişkinin "id" değerini üreten parçayı gösterelim. Bu id bir sonraki script'te ilişkinin detaylarını görmemiz için kullanılacak. Son kısımdaki tablo isimleri parametrelerini değiştirerek bu sorguları istediğiniz  tablo için çalıştırabilirsiniz.

SELECT 
--[Join5].[Ordinal] AS [C1], 
--[UnionAll4].[CatalogName] AS [C2], 
--[UnionAll4].[SchemaName] AS [C3], 
--[UnionAll4].[Name] AS [C4], 
--[Join5].[Name1] AS [C5], 
[UnionAll5].[CatalogName] AS [C6], 
[UnionAll5].[SchemaName] AS [C7], 
[UnionAll5].[Name] AS [C8], 
--[Join5].[Name2] AS [C9], 
[Extent2].[Name] AS [Name], 
[Extent1].[Id] AS [Id]--, 
--CASE WHEN ([Extent1].[DeleteRule] = 'CASCADE') THEN cast(1 as bit) WHEN ([Extent1].[DeleteRule] <> 'CASCADE') THEN cast(0 as bit) END AS [C10]
FROM 

	(SELECT
			quotename(rc.CONSTRAINT_SCHEMA) + quotename(rc.CONSTRAINT_NAME) [Id]
			, CAST(rc.UPDATE_RULE as nvarchar(11)) [UpdateRule]
			, CAST(rc.DELETE_RULE as nvarchar(11)) [DeleteRule]
			FROM
			INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
		  ) AS [Extent1]
	INNER JOIN (
			SELECT
			quotename(tc.CONSTRAINT_SCHEMA) + quotename(tc.CONSTRAINT_NAME) [Id]
			, quotename(tc.TABLE_SCHEMA) + quotename(tc.TABLE_NAME) [ParentId]
			,   tc.CONSTRAINT_NAME [Name]
			,   tc.CONSTRAINT_TYPE [ConstraintType]
			,   CAST(CASE tc.IS_DEFERRABLE WHEN 'NO' THEN 0 ELSE 1 END as bit) [IsDeferrable]
			,   CAST(CASE tc.INITIALLY_DEFERRED WHEN 'NO' THEN 0 ELSE 1 END as bit) [IsInitiallyDeferred]
			FROM
			INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
			WHERE tc.TABLE_NAME IS NOT NULL
		  ) AS [Extent2] ON [Extent1].[Id] = [Extent2].[Id]


    
	LEFT OUTER JOIN        
	(SELECT 
		3 AS [C1], 
		[Extent13].[Id] AS [Id], 
		[Extent13].[Name] AS [Name], 
		[Extent13].[CatalogName] AS [CatalogName], 
		[Extent13].[SchemaName] AS [SchemaName]
		FROM (
			SELECT
			quotename(TABLE_SCHEMA) + quotename(TABLE_NAME) [Id]
			,   TABLE_CATALOG [CatalogName]
			,   TABLE_SCHEMA [SchemaName]
			,   TABLE_NAME    [Name]
			FROM
			INFORMATION_SCHEMA.TABLES
			WHERE
			TABLE_TYPE = 'BASE TABLE'
		  ) AS [Extent13]
	UNION ALL
		SELECT 
		12 AS [C1], 
		[Extent14].[Id] AS [Id], 
		[Extent14].[Name] AS [Name], 
		[Extent14].[CatalogName] AS [CatalogName], 
		[Extent14].[SchemaName] AS [SchemaName]
		FROM (
			SELECT
			quotename(TABLE_SCHEMA) + quotename(TABLE_NAME) [Id]
			,   TABLE_CATALOG             [CatalogName]
			,   TABLE_SCHEMA              [SchemaName]
			,   TABLE_NAME                [Name]
			,   VIEW_DEFINITION           [ViewDefinition]
			,   CAST( CASE IS_UPDATABLE WHEN 'YES' THEN 1 WHEN 'NO' THEN 0 ELSE 0 END as bit) [IsUpdatable]
			FROM
			INFORMATION_SCHEMA.VIEWS
			WHERE
			NOT (TABLE_SCHEMA = 'dbo'
			AND TABLE_NAME in('syssegments', 'sysconstraints')
			AND SUBSTRING(CAST(SERVERPROPERTY('productversion') as varchar(20)),1,1) = 8)
		  ) AS [Extent14]) AS [UnionAll5] ON (3 = [UnionAll5].[C1]) AND ([Extent2].[ParentId] = [UnionAll5].[Id])
	WHERE 
	(
		
		(
			([UnionAll5].[CatalogName] LIKE '...') AND 
			([UnionAll5].[SchemaName] LIKE 'dbo') AND 
			([UnionAll5].[Name] LIKE 'Table_Mtmp')
		)

		OR 
		(
			([UnionAll5].[CatalogName] LIKE '...') AND 
			([UnionAll5].[SchemaName] LIKE 'dbo') AND 
			([UnionAll5].[Name] LIKE 'Table_Ttmp')
		)
	)

 

Bu scriptin çıktısı şu şekilde olmalı. Eğer Table_Ttmp ninde FK bağlantıları olsaydı onlarda gelecekti

 

 

Şimdi paylaşacaım script ise bu id değerine göre iki tablo arasında hangi kolonlar arasında bu ilişkinin olduğunu gösteriyor

SELECT
[Extent3].[Ordinal] AS [Ordinal], 
0 AS [C1], 
[Extent3].[ConstraintId] AS [ConstraintId], 
6 AS [C2], 
[Extent3].[FromColumnId] AS [FromColumnId], 
6 AS [C3], 
[Extent3].[ToColumnId] AS [ToColumnId]
FROM (
  SELECT
  quotename(FC.CONSTRAINT_SCHEMA) + quotename(FC.CONSTRAINT_NAME) + quotename(cast(FC.ORDINAL_POSITION as nvarchar(30))) [Id]
  ,   quotename(PC.TABLE_SCHEMA) + quotename(PC.TABLE_NAME) + quotename(PC.COLUMN_NAME) [ToColumnId]
  ,   quotename(FC.TABLE_SCHEMA) + quotename(FC.TABLE_NAME) + quotename(FC.COLUMN_NAME) [FromColumnId]
  ,   quotename(FC.CONSTRAINT_SCHEMA) + quotename(FC.CONSTRAINT_NAME) [ConstraintId]
  ,   FC.ORDINAL_POSITION [Ordinal]
  FROM 
	INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 
	  INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS PC /* PRIMARY KEY COLS*/ ON       
		RC.UNIQUE_CONSTRAINT_SCHEMA = PC.CONSTRAINT_SCHEMA  
		AND      RC.UNIQUE_CONSTRAINT_NAME    = PC.CONSTRAINT_NAME
      INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS FC /* FOREIGN KEY COLS*/ ON       
		RC.CONSTRAINT_SCHEMA = FC.CONSTRAINT_SCHEMA         
		AND      RC.CONSTRAINT_NAME    = FC.CONSTRAINT_NAME 
		AND   PC.ORDINAL_POSITION = FC.ORDINAL_POSITION
) AS [Extent3]

where ('[dbo][FK_Table_Mtmp2_Table_T]' = [ConstraintId])

 

Çıktısı şu şekilde olmalı

 

 

Yukarıdaki çıktıdan anlaşıldığı üzere FromColumnId de gözüken Table_Mtmp tablosunun Table_M_ID kolonu ile ToColumnId de gözüken Table_Ttmp ve Table_T_ID arasında [dbo][FK_Table_Mtmp2_Table_T] idli bir bağlantı bulunmaktadır. Eğer bu satır boş gelirse EF FK ilişkisini (association) kuramıyor.

Aslında amacımıza ulaştık iki tablo arasında ilişkiyi gördük. Ama asıl çözüm sağlayan adım burada başlıyor. Burada satır boş gelirse sorunu nasıl anlayacağız. Çünkü bizde ilişki olduğu halde satır burada boş geliyordu. İşte onun tahlilinide bu script içinden aldığım son script ile paylaşarak yapacağız.

Select * from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where '[dbo][FK_Table_Mtmp2_Table_T]' =  quotename(CONSTRAINT_SCHEMA) + quotename(CONSTRAINT_NAME) 
Select * from INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS where CONSTRAINT_SCHEMA = 'dbo' AND CONSTRAINT_NAME = 'FK_Table_Mtmp2_Table_T'
Select * from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where CONSTRAINT_SCHEMA = 'dbo' AND CONSTRAINT_NAME = 'PK__Table_Tt__96E7C6DB2B803210'

Ekran Çıktısı

  

Burada artık bu FK ilişkisinin hangi Constraint Name ler ile hangi tablolar arasında kurulduğu net olarak gözüküyor. Scripteki birinci tablo FK sahibi olan Table_Mtmp tablosun ait, ikinci satır PK (Primary key) tablosu ile ilikiliyi kurulan PK ya ait contraint'in isminin saklandığı UNIQUE_CONSTRAINT_NAME kolonunu içeriyor. Üçüncü satır aslında birinci satırla aynı KEY_COLUMN_USAGE Information Schemasına bakıyor ancak artık PK ya ait olan constraint name le bakıyor.

Bizim sorun neydi bari onuda söyliyeyim :) İşte 2 Satırda aldığımız  UNIQUE_CONSTRAINT_NAME PK Contraint name i üçüncü satırda where cümlesine konulunca boş geliyordu. Sebebi meğerse aynı PK değeri üzerinde aynı özelliklere sahip bir index tanımlanmış ve bağlantı PK Contraint Key'i ile değilde bu index ile kurulmuş. O index ise  KEY_COLUMN_USAGE Information Schemasında gözükmediği için EF FK ilişkisini kuramıyordu. O index'i sildik sorun çözüldü. Artık son scriptteki 3 satırda dolu gelmeye başladı :)

 

İyi çalışmalar.



LinqKit Linq dynamic sql parameter

clock Şubat 11, 2016 13:47 by author OzgurOzvaris

Merhaba Arkadaşlar,

Kaynaklar

What is LINQKit?

Dynamically Composing Expression Predicates

How does PredicateBuilder work

linqpad - adding reference to assembly to using custom types

How does LINQPad reference other classes

Building LINQ Queries at Runtime in C#

LinqPad adds an S to the end of every table

Writing Methods and Classes in LINQPad

Entity Framework te Linq ile yapacağınız geliştirmelerde. ilk karşınıza çıkacak zorluklardan bir tanesi dinamik olarak parametre eklemek.

LinqPad malumunuz uzun süredir linq cümleleri geliştirmek için kullanılan bir araç. Gerek database bağlantılı gerekse database bağlantısı olmadan linq sorgularının çıktılarını inceleyebiliryorsunuz. Bu bloğu sanki LinqPad ile ilgili bası basamakları biliyormuşsunuz gibi bazı ön kabullerle başlayacağım. Bu Ön kabuller.

1 - Temel Linq bilgisi

2 - LinqPad download ve install edilmesi

3 - Database connection oluşturulması

Bu ön kabuller üzerinden devam ederek sizlere dinamik bir linq sorgusu nasıl geliştirilir izah etmeye çalışacağım.

LinqPad adresinden gerekli setup işlemlerini yapıyor ve LinqPad'i açıyorsunuz

 

- Öncelikli olarak Sol menüdeki Add Connection bölümünü tıklayarak connection oluşturmanız gerekmektedir.Default linki kullanarak devam et diyerek connection kurabilirsiniz. (Güncelleme 25.04.2016 )Connection oluştururken "Pluralize" seçeneğinin açık olup olmadığını dikkat edin. Ben kapalı olarak kullandığım için bir müddet neden Expandable komutum çalışmadı diye zaman harcadım. Meğerse tablo adının sonuna "s" eklemiş

 

- Şimdi sıra geldi dinamik parametreler eklememize yardımcı olan LinqKit dll'ini yüklemeye. Bu dll'i nuget yada What is LINQKit? makalesinin altındaki download linki ile yükleyebilirsiniz. 

-  LinqKit kurduğunuz yerden LinqPad'a refernce olarak eklemeniz gerekmektedir. Bunun için F4 Tuşuna basmalısınız. Karşınıza Add Reference penceresi çıkacak. Browse seçilerek LinqKit işaret edildikten sonra, Additional Namespace inmport bölümünden LinqKit adı yazılarak LinqPad'in artık LinqKit'i tanıması sağlanır.

 

- Daha sonra Language seçmelerinden c# statements seçmelisiniz.

 

Ben kendi örneğimde FSYS_USERS tabloma OnlyActive User parametresini test ettim. Siz kendi tablolarınızı çağırarak test yapabilirsiniz. Bu arada Context adı yazmadan direk olarak tablo adı yazdığıma dikkat edin.

var OnlyActiveUsers = true;
Expression<Func<FSYS_USERS, bool>> FSYS_USERSPredicate = p1 => true;

            if (OnlyActiveUsers)
            {
                FSYS_USERSPredicate = FSYS_USERSPredicate.And(z => z.FSTATUS == 'A');
            }
			
var x = from c in FSYS_USERS.Where(c => true).Where(FSYS_USERSPredicate).OrderBy(o=> o.ADSOYAD)
                    select c;

 //           x.ToList();
 
 x.Dump();

 

Yukarıdaki örnekte Eğer OnlyActiveUsers set edilirse linq cumlesine bir predicate daha ekleniyor. Run tuşuna basarak aşağıdaki tablardan dönüş değerlerini, sonuçta oluşan dinamik linq cümlesini ve sql'e giden cümleyi görebilirsiniz. Dump Komutu LinqPad'in aşağıda listeyi görebilmenizi sağlayan bir Extension komutu. ToList'ini alıp aşağıda sonuç tabloayu görmenizi sağlıyor.

Burada gerekli testleri yaptıktan sonra artık sonuç fonksyonumuzu oluşturabiliriz.

public IEnumerable<FSYS_USERS> GetActiveUsersShortInfo(bool OnlyActiveUsers)
        {
            //var FSYS_USERSPredicate = PredicateBuilder.True<FSYS_USERS>();

            //if (OnlyActiveUsers)
            //{
            //    FSYS_USERSPredicate.And(z => z.FSTATUS == "A");
            //}

            //var x = from c in MasterContext.FSYS_USERS.AsExpandable().Where(FSYS_USERSPredicate.Compile())
            //        select c;

            Expression<Func<FSYS_USERS, bool>> FSYS_USERSPredicate = p1 => true;

            if (OnlyActiveUsers)
            {
                FSYS_USERSPredicate = FSYS_USERSPredicate.And(z => z.FSTATUS == "A");
            }

            var x = from c in MasterContext.FSYS_USERS.AsExpandable().Where(c => true).Where(FSYS_USERSPredicate.Compile()).OrderBy(o=> o.ADSOYAD)
                    select c;

            return x.ToList();
        }

 

Bu şekilde tam olarak dinamik bir parametreyi Entity Framework yapımıza eklemiş olduk. Method daki AsExpandable ve Compile komutları LinqKit aracılığı ile gelen extension komutlar.

(Güncelleme 25.04.2016) Eğer c# statement linq cümlesinde bir class yada method kullanmak isterseniz. Bunuda düşünmüşler :) tek yapmanız gereken statement sonunda "}" ile linq bölümünü eklemek ve ardına istediğiniz kadar method ve class ekleyebilirsiniz. Writing Methods and Classes in LINQPad Burada detaylı bir şekilde anlatıyor. Denedim çok güzel çalışıyor.

 

İyi çalışmalar.



Entity Framework Toint64 , Toint32 vs.

clock Eylül 5, 2014 18:33 by author OzgurOzvaris

Merhaba,

Entitiy Frameworkte bir sayıya type cast yapacaksanız convert.ToInt32 gibi metorları kullanmayın runtime da hata alırsınız. Bunun yerine direk olarak (long) diyerek cast edin. Bu durumda sql cast fonksyonu ile sql'e göndericektir.

İyi çalışmalar.



Entity Framework left outer join

clock Eylül 4, 2014 14:03 by author OzgurOzvaris

Merhaba Arkadaşlar,

Kayneklar

Left Outer Joins in LINQ with Entity Framework

LEFT JOIN or RIGHT JOIN using LINQ Entity-Framework

Entity Framework (EF) giriş yazımızda, bazen EF de sql de yapılan basit işlemlerin EF diline göre yapılması gerektiğinden bahsetmiştik. Buna "Left Join " İşlemi güzel bir örnek olabilir. SQL de sadece iki kelime ile yaptığınız left join işlemi iki farlı yöntem var.

Bunlardan birincisi dbSetimizin direk olarak DefaultIfEmpty Metodu ile bağlanması, ikincisi ise dbSetimizin bir variable içine atılıp daha sonra DefaultIfEmpty ile bağlanması.

Standar join işlemi

from o in Orders
join od in OrderDetails on o.OrderID equals od.OrderID
select new {o, od}
SELECT 
    [Extent1].*, [Extent2.*
FROM  [dbo].[Orders] AS [Extent1]
    INNER JOIN [dbo].[OrderDetails] AS [Extent2] ON [Extent1].[OrderID] = [Extent2].[OrderID]

Direk DefaultDefaultIfEmpty

from c in Customers
from o in Orders
    .Where (o => o.CustomerID == c.CustomerID)
    .DefaultIfEmpty()
select new {c, o};
SELECT 
    1 AS [C1], 
    [Extent1].*, [Extent2}.*
    FROM  [dbo].[Customers] AS [Extent1]
    LEFT OUTER JOIN [dbo].[Orders] AS [Extent2] ON ([Extent2].[CustomerID] = [Extent1].[CustomerID])
       AND ([Extent2].[CustomerID] IS NOT NULL)

Değişken içine atarak

var applicantList = (from app in context.APPLICANTs
join a in context.Profiles
on app.Profile_id equals a.PROFILE_ID into output
from j in output.DefaultIfEmpty()
select new { APPLICANT_ID = app.APPLICANT_ID, Applicant_Name = (j == null ? app.Applicant_Name : j.Applicant_Name) }).Take(1000).AsEnumerable();

Complex bir örnek

var x = from i in (DbContext as Krnc_ReSellerEntities).FSYS_LABELS
                    join e in (DbContext as Krnc_ReSellerEntities).FSYS_DICTIONARY
                    //.DefaultIfEmpty()
                       .Where(c => c.FSYS_LANGUAGE.FSLANG_ID == FSLANG_ID)
                        on 
                        new { Table_ID = i.TBL_ID, Field_ID = i.FSLABEL_ID } equals
                        new { Table_ID = e.TBL_ID, Field_ID = e.FIELD_ID }
                        //into output
                        //from k in output.DefaultIfEmpty()
                    join e1 in (DbContext as Krnc_ReSellerEntities).FSYS_DICTIONARY
                        //.DefaultIfEmpty()
                        .Where(c => c.FSYS_LANGUAGE.FSLANG_ID == SecondFSLANG_ID)
                        on
                        new { Table_ID = i.TBL_ID, Field_ID = i.FSLABEL_ID } equals
                        new { Table_ID = e1.TBL_ID, Field_ID = e1.FIELD_ID }
                        into output1
                        from j in output1.DefaultIfEmpty()  
                    //where k.FSYS_LANGUAGE.FSLANG_ID == SecondFSLANG_ID && j.FSYS_LANGUAGE.FSLANG_ID == SecondFSLANG_ID
                    select new LabelDefinitionView {
                        KeyField = i.FSLABEL_ID.ToString() + ";" + e.FSYS_DIC_ID.ToString() + ";" + j.FSYS_DIC_ID.ToString(), 
                        TBL_ID = i.TBL_ID,
                        FSLABEL_ID = i.FSLABEL_ID,
                        LABEL_TYPE = i.LABEL_TYPE,
                        KOD = i.KOD,
                        FSYS_DIC_ID = e.FSYS_DIC_ID, 
                        Description = e.TANIM_ML,
                        Second_FSYS_DIC_ID = j.FSYS_DIC_ID,
                        SecondLang_Description = j.TANIM_ML
                    };
 
SELECT 
    [Extent1].[LABEL_TYPE] AS [LABEL_TYPE], 
     CAST( [Extent1].[FSLABEL_ID] AS nvarchar(max)) + N';' +  CAST( [Extent2].[FSYS_DIC_ID] AS nvarchar(max)) + N';' + CASE WHEN (CASE WHEN ([Extent3].[FSYS_DIC_ID] IS NULL) THEN N'' ELSE  CAST( [Extent3].[FSYS_DIC_ID] AS nvarchar(max)) END IS NULL) THEN N'' WHEN ([Extent3].[FSYS_DIC_ID] IS NULL) THEN N'' ELSE  CAST( [Extent3].[FSYS_DIC_ID] AS nvarchar(max)) END AS [C1], 
    [Extent1].[TBL_ID] AS [TBL_ID], 
    [Extent1].[FSLABEL_ID] AS [FSLABEL_ID], 
    [Extent1].[KOD] AS [KOD], 
    [Extent2].[FSYS_DIC_ID] AS [FSYS_DIC_ID], 
    [Extent2].[TANIM_ML] AS [TANIM_ML], 
    [Extent3].[FSYS_DIC_ID] AS [FSYS_DIC_ID1], 
    [Extent3].[TANIM_ML] AS [TANIM_ML1]
    FROM   [dbo].[FSYS_LABELS] AS [Extent1]
    INNER JOIN [dbo].[FSYS_DICTIONARY] AS [Extent2] ON ([Extent1].[TBL_ID] = [Extent2].[TBL_ID]) AND ([Extent1].[FSLABEL_ID] = [Extent2].[FIELD_ID])
    LEFT OUTER JOIN [dbo].[FSYS_DICTIONARY] AS [Extent3] ON ([Extent3].[FSLANG_ID] = @p__linq__1) AND ([Extent1].[TBL_ID] = [Extent3].[TBL_ID]) AND ([Extent1].[FSLABEL_ID] = [Extent3].[FIELD_ID])
    WHERE [Extent2].[FSLANG_ID] = @p__linq__0',N'@p__linq__1 bigint,@p__linq__0 bigint',@p__linq__1=2,@p__linq__0=1

 



Entity Framework Join

clock Eylül 3, 2014 12:37 by author OzgurOzvaris

Merhaba Arkadaşlar,

Kaynak,

Entity Framework Query for inner join

Entity Framework Join 3 Tables

Entity Framework LINQ joining 5 tables on multiple columns (impossible?!)

Joining tables using more than one column in Linq To Entities

The type arguments cannot be inferred from the query...

Bazen database tarafında tablolar birbiri ile ilişkili olmadığında yada daha esnek conditionlar eklemek istediğinizde (ilişkili ve derinlerdeki tablolara condition eklemek istediğiniz durumlar gibi) EF'ün "Join" komutuna ihiyaç duyabilir siniz.

 Güzel bir örnek olmasından dolayı kaynaklar'dan birinde geçen örneği paylaşıyorum.

from s in db.Services
join sa in db.ServiceAssignments on s.Id equals sa.ServiceId
where sa.LocationId == 1
select s

Eğer birden fazla kolon joinlemek isterseniz...

var match = from t1 in context.cKNA1
             join t2 in context.cKNB1 on 
                    new { t1.KUNNR, t1.RowId } equals 
                    new { t2.KUNNR, t2.RowId }
             join t3 in context.cKNVV on 
                    new { t2.KUNNR, t2.RowId } equals 
                    new { t3.KUNNR, t3.RowId }
             join t4 in context.cKNVH on 
                    new { t3.KUNNR, t3.RowId } equals 
                    new { t4.KUNNR, t4.RowId }
    SELECT t1.KUNNR;


Yada ikinci bir syntax olarak...

from a in Table1s 
from b in Table2s
where a.ID1Table1 == b.ID1Table2 && a.ID2Table1 == b.ID2Table2
select new {a.ID1Table1, a.ID2Table1, a.Value1Table1, b.ID3Table2, b.Value1Table2}


Eğer yapılan join işlemlerinde field isimleri birbirini eşit değilse "The type arguments cannot be inferred from the query..." alabilirsiniz. Böyle bir durumda "new" komutu ile oluşturduğunuz class alanlarına ortak isimler vermelisiniz.

join inventory in Models.Inventories on new
{
	Supplier = equivalency.EquivalencySupplier,
	Part = equivalency.EquivalencyPart
} equals new
{
	Supplier = inventory.Supplier,
	Part = inventory.Part
}

 

İyi çalışmalar.



Entity Framework'e Giriş

clock Eylül 3, 2014 11:47 by author OzgurOzvaris

Merhaba Arkadaşlar,

Entity Framework (EF) ile ilgili pek yazı kaleme almadım. Aslında bu tarafta hatırı sayılır miktarda Entitiy Framework tecrübesi birikti. Sizlerle ara ara bunlarıda paylaşmaya çalşacağım. Aslında bu yazıda "Entity Framework Join" konusuna deyinecektim ancak bu vesile ile biraz Entity Frame work'un genel konularına değineyim.

Entity Framework emsalleri ile karşılaştırılınca gerçekten bambaşka bir dünya. Bazen insanı çılgına çevirecek kadar zor, bazende ya bunuda mı yapıyor helal olsun bu adamlara diyecek kadar tatminkar. Bazende bunu nasıl hâlâ eklememişler diyecek kadar sizi üzen, sürekli size karma karışık duygular yaşatan, sürekli gelişen bir sistem. Zaten 6.0 versiyonunu görmesi ve hala hızla gelişmeside buna en basit örnek.

Ayrıca hâlâ güçlü bir yazılımının data katmanı EF ile geliştirilebilir mi diye piyasada ciddi endişeler var. Kabul elmek gerek ki "SQL" database ile kurulan çok ciddi bir iletişim yöntemi ve belkide EF hiçbir zaman onun kadar güçlü olamayacak. Ancak sql ve EF'ü kıyaslamak bana adil gelmiyor. EF gücünü sistemlerinden (Code First, Design First, Database First, POCO vb. ) alıyor. EF adeta kıyas edersek yazı dünyasındaki Word uygulaması yolun da gidiyor, sql ise database dünyasının karakalemi gibi. Sql'de varyasyonlar bir hayli çoğalmış durumda tabi ki EF'de varyasyonlar o kadar çok değil.

Entitiy Framework'te doğru synax ve doğru sql çıktısı çok önemli. Gerçekten çok güçlü bir yapı. Ancak sadece yazdım bitti diyemiyorsunuz. Bir şekilde alışana kadar sql profiler'dan ve ya başka şekillerde EF'ün efektif SQL cümleleri üretip üretmediğini kontrol etmeniz gerekiyor.

Aslında bu makaleye "Entity Framework Join" demiştim ancak yazı başka yöne doğru gidince başlığı şimdiki başığa çevirdim.

Birazdan "Entity Framework Join" makalemide yayınlayacağım inşallah.

Herkese iyi çalışmalalar.



Hakkımızda  AboneOl 

Blog Yayınımıza Hoşgeldiniz.

Month List

RecentPosts

Sign In