다음을 통해 공유


방법: LINQ to SQL 데이터 소스를 사용하여 데이터 서비스 만들기(WCF Data Services)

WCF Data Services 에서는 엔터티 데이터를 데이터 서비스로 노출합니다. 리플렉션 공급자를 사용하면 IQueryable 구현을 반환하는 멤버를 노출하는 클래스를 기반으로 하여 데이터 모델을 정의할 수 있습니다. 데이터 소스의 데이터를 업데이트할 수 있으려면 이러한 클래스도 IUpdatable 인터페이스를 구현해야 합니다. 자세한 내용은 데이터 서비스 공급자(WCF Data Services)를 참조하십시오. 이 항목에서는 리플렉션 공급자를 사용하여 Northwind 샘플 데이터베이스에 액세스하는 LINQ to SQL 클래스를 만드는 방법과 이러한 데이터 클래스를 기반으로 하는 데이터 서비스를 만드는 방법을 보여 줍니다.

프로젝트에 LINQ to SQL 클래스를 추가하려면

  1. Visual Basic 또는 C# 응용 프로그램의 프로젝트 메뉴에서 새 항목 추가를 클릭합니다.

  2. LINQ to SQL 클래스 템플릿을 클릭합니다.

  3. 이름을 Northwind.dbml로 변경합니다.

  4. 추가를 클릭합니다.

    Northwind.dbml 파일이 프로젝트에 추가되고 Object Relational Designer(O/R Designer)가 열립니다.

  5. 서버/데이터베이스 탐색기에서 Northwind 아래의 테이블을 확장하고 Customers 테이블을 Object Relational Designer(O/R Designer)로 끌어 옵니다.

    Customer 엔터티 클래스가 만들어져 디자인 화면에 표시됩니다.

  6. Orders, Order_DetailsProducts 테이블에 대해 6단계를 반복합니다.

  7. LINQ to SQL 클래스를 나타내는 새 .dbml 파일을 마우스 오른쪽 단추로 클릭하고 코드 보기를 클릭합니다.

    이렇게 하면 DataContext 클래스에서 상속되는 클래스(이 경우 NorthwindDataContext)의 partial 클래스 정의가 포함된 Northwind.cs라는 새 코드 숨김 페이지가 만들어집니다.

  8. Northwind.cs 코드 파일의 내용을 다음 코드로 바꿉니다. 이 코드는 LINQ to SQL에서 생성된 DataContext 및 데이터 클래스를 확장하여 리플렉션 공급자를 구현합니다.

    Imports System.ComponentModel
    Imports System.Collections
    Imports System.Linq
    Imports System.Reflection
    Imports System.Data.Linq
    Imports System.Data.Linq.Mapping
    Imports System.Data.Services
    Imports System.Data.Services.Common
    
    ' Define the key properties for the LINQ to SQL data classes.
    <DataServiceKeyAttribute("CustomerID")> _
    Partial Public Class Customer
    End Class
    <DataServiceKeyAttribute("ProductID")> _
    Partial Public Class Product
    End Class
    <DataServiceKeyAttribute("OrderID")> _
    Partial Public Class Order
    End Class
    <DataServiceKeyAttribute("OrderID", "ProductID")> _
    Partial Public Class Order_Detail
    End Class
    #Region "IUpdatable implementation"
    ' Define the IUpdatable implementation for LINQ to SQL.
    Partial Public Class NorthwindDataContext
        Implements IUpdatable
        ' Creates an object in the container.
        Function CreateResource(ByVal containerName As String, ByVal fullTypeName As String) _
            As Object Implements IUpdatable.CreateResource
    
            Dim t = Type.GetType(fullTypeName, True)
            Dim table = GetTable(t)
            Dim resource = Activator.CreateInstance(t)
            table.InsertOnSubmit(resource)
            Return resource
        End Function
        ' Gets the object referenced by the resource.
        Function GetResource(ByVal query As IQueryable, ByVal fullTypeName As String) As Object _
         Implements IUpdatable.GetResource
            Dim resource = query.Cast(Of Object)().SingleOrDefault()
    
            ' fullTypeName can be null for deletes
            If fullTypeName IsNot Nothing AndAlso resource.GetType().FullName <> fullTypeName Then
                Throw New ApplicationException("Unexpected type for this resource.")
            End If
            Return resource
        End Function
        ' Resets the value of the object to its default value.
        Function ResetResource(ByVal resource As Object) As Object _
            Implements IUpdatable.ResetResource
            Dim t = resource.GetType()
            Dim table = Mapping.GetTable(t)
            Dim dummyResource = Activator.CreateInstance(t)
            For Each member In table.RowType.DataMembers
    
                If Not member.IsPrimaryKey AndAlso Not member.IsDeferred AndAlso _
                    Not member.IsAssociation AndAlso Not member.IsDbGenerated Then
                    Dim defaultValue = member.MemberAccessor.GetBoxedValue(dummyResource)
                    member.MemberAccessor.SetBoxedValue(resource, defaultValue)
                End If
                Next
            Return resource
        End Function
        ' Sets the value of the given property on the object.
        Sub SetValue(ByVal targetResource As Object, ByVal propertyName As String, _
                     ByVal propertyValue As Object) Implements IUpdatable.SetValue
            Dim table = Mapping.GetTable(targetResource.GetType())
            Dim member = table.RowType.DataMembers.Single(Function(x) x.Name = propertyName)
            member.MemberAccessor.SetBoxedValue(targetResource, propertyValue)
        End Sub
        ' Gets the value of a property on an object.
        Function GetValue(ByVal targetResource As Object, ByVal propertyName As String) _
        As Object Implements IUpdatable.GetValue
            Dim table = Mapping.GetTable(targetResource.GetType())
            Dim member = _
            table.RowType.DataMembers.Single(Function(x) x.Name = propertyName)
            Return member.MemberAccessor.GetBoxedValue(targetResource)
        End Function
        ' Sets the related object for a reference.
        Sub SetReference(ByVal targetResource As Object, ByVal propertyName As String, _
                         ByVal propertyValue As Object) Implements IUpdatable.SetReference
            CType(Me, IUpdatable).SetValue(targetResource, propertyName, propertyValue)
        End Sub
    ' Adds the object to the related objects collection.
        Sub AddReferenceToCollection(ByVal targetResource As Object, ByVal propertyName As String, _
                                     ByVal resourceToBeAdded As Object) _
                                     Implements IUpdatable.AddReferenceToCollection
            Dim pi = targetResource.GetType().GetProperty(propertyName)
            If pi Is Nothing Then
                Throw New Exception("Can't find property")
            End If
            Dim collection = CType(pi.GetValue(targetResource, Nothing), IList)
            collection.Add(resourceToBeAdded)
        End Sub
        ' Removes the object from the related objects collection.
        Sub RemoveReferenceFromCollection(ByVal targetResource As Object, ByVal propertyName As String, _
                                          ByVal resourceToBeRemoved As Object) _
                                          Implements IUpdatable.RemoveReferenceFromCollection
            Dim pi = targetResource.GetType().GetProperty(propertyName)
            If pi Is Nothing Then
                Throw New Exception("Can't find property")
            End If
            Dim collection = CType(pi.GetValue(targetResource, Nothing), IList)
            collection.Remove(resourceToBeRemoved)
        End Sub
            ' Deletes the resource.
        Sub DeleteResource(ByVal targetResource As Object) _
        Implements IUpdatable.DeleteResource
            Dim table = GetTable(targetResource.GetType())
            table.DeleteOnSubmit(targetResource)
        End Sub
        ' Saves all the pending changes.
        Sub SaveChanges() Implements IUpdatable.SaveChanges
            SubmitChanges()
        End Sub
        ' Returns the actual instance of the resource represented 
        ' by the resource object.
        Function ResolveResource(ByVal resource As Object) As Object Implements IUpdatable.ResolveResource
            Return resource
        End Function
            ' Reverts all the pending changes.
        Sub ClearChanges() Implements IUpdatable.ClearChanges
            ' Raise an exception as there is no real way to do this with LINQ to SQL.
            ' Comment out the following line if you'd prefer a silent failure
            Throw New NotSupportedException()
        End Sub
    End Class
    #End Region
    
    using System;
    using System.ComponentModel;
    using System.Collections;
    using System.Linq;
    using System.Reflection;
    using System.Data.Linq;
    using System.Data.Linq.Mapping;
    using System.Data.Services;
    using System.Data.Services.Common;
    
    namespace NorthwindService
    {
        // Define the key properties for the LINQ to SQL data classes.
        [DataServiceKeyAttribute("CustomerID")]
        public partial class Customer { }
    
        [DataServiceKeyAttribute("ProductID")]
        public partial class Product { }
    
        [DataServiceKeyAttribute("OrderID")]
        public partial class Order { }
    
        [DataServiceKeyAttribute("OrderID", "ProductID")]
        public partial class Order_Detail { }
    
        #region IUpdatable implementation
        // Define the IUpdatable implementation for LINQ to SQL.
        public partial class NorthwindDataContext : IUpdatable
        {
            // Creates an object in the container.
            object IUpdatable.CreateResource(string containerName, string fullTypeName)
            {
                Type t = Type.GetType(fullTypeName, true);
                ITable table = GetTable(t);
                object resource = Activator.CreateInstance(t);
                table.InsertOnSubmit(resource);
                return resource;
            }
    
            // Gets the object referenced by the resource.
            object IUpdatable.GetResource(IQueryable query, string fullTypeName)
            {
                object resource = query.Cast<object>().SingleOrDefault();
    
                // fullTypeName can be null for deletes
                if (fullTypeName != null && resource.GetType().FullName != fullTypeName)
                    throw new ApplicationException("Unexpected type for this resource.");
                return resource;
            }
    
    
            // Resets the value of the object to its default value.
            object IUpdatable.ResetResource(object resource)
            {
                Type t = resource.GetType();
                MetaTable table = Mapping.GetTable(t);
                object dummyResource = Activator.CreateInstance(t);
                foreach (var member in table.RowType.DataMembers)
                {
                    if (!member.IsPrimaryKey && !member.IsDeferred &&
                        !member.IsAssociation && !member.IsDbGenerated)
                    {
                        object defaultValue = member.MemberAccessor.GetBoxedValue(dummyResource);
                        member.MemberAccessor.SetBoxedValue(ref resource, defaultValue);
                    }
                }
                return resource;
            }
    
            // Sets the value of the given property on the object.
            void IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue)
            {
                MetaTable table = Mapping.GetTable(targetResource.GetType());
                MetaDataMember member = table.RowType.DataMembers.Single(x => x.Name == propertyName);
                member.MemberAccessor.SetBoxedValue(ref targetResource, propertyValue);
            }
    
            // Gets the value of a property on an object.
            object IUpdatable.GetValue(object targetResource, string propertyName)
            {
                MetaTable table = Mapping.GetTable(targetResource.GetType());
                MetaDataMember member =
                    table.RowType.DataMembers.Single(x => x.Name == propertyName);
                return member.MemberAccessor.GetBoxedValue(targetResource);
            }
    
            // Sets the related object for a reference.
            void IUpdatable.SetReference(
                object targetResource, string propertyName, object propertyValue)
            {
                ((IUpdatable)this).SetValue(targetResource, propertyName, propertyValue);
            }
    
            // Adds the object to the related objects collection.
            void IUpdatable.AddReferenceToCollection(
                object targetResource, string propertyName, object resourceToBeAdded)
            {
                PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
                if (pi == null)
                    throw new Exception("Can't find property");
                IList collection = (IList)pi.GetValue(targetResource, null);
                collection.Add(resourceToBeAdded);
            }
    
            // Removes the object from the related objects collection.
            void IUpdatable.RemoveReferenceFromCollection(
                object targetResource, string propertyName, object resourceToBeRemoved)
            {
                PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
                if (pi == null)
                    throw new Exception("Can't find property");
                IList collection = (IList)pi.GetValue(targetResource, null);
                collection.Remove(resourceToBeRemoved);
            }
    
            // Deletes the resource.
            void IUpdatable.DeleteResource(object targetResource)
            {
                ITable table = GetTable(targetResource.GetType());
                table.DeleteOnSubmit(targetResource);
            }
    
            // Saves all the pending changes.
            void IUpdatable.SaveChanges()
            {
                SubmitChanges();
            }
    
            // Returns the actual instance of the resource represented 
            // by the resource object.
            object IUpdatable.ResolveResource(object resource)
            {
                return resource;
            }
    
            // Reverts all the pending changes.
            void IUpdatable.ClearChanges()
            {
                // Raise an exception as there is no real way to do this with LINQ to SQL.
                // Comment out the following line if you'd prefer a silent failure
                throw new NotSupportedException();
            }
        #endregion
        }
    }
    

LINQ to SQL 기반 데이터 모델을 사용하여 데이터 서비스를 만들려면

  1. 솔루션 탐색기에서 ASP.NET 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고 새 항목 추가를 클릭합니다.

  2. 새 항목 추가 대화 상자에서 WCF Data Service를 선택합니다.

  3. 서비스의 이름을 지정하고 확인을 클릭합니다.

    Visual Studio에서 새 서비스의 XML 태그와 코드 파일을 만듭니다. 기본적으로 코드 편집기 창이 열립니다.

  4. 데이터 서비스 코드에서 데이터 서비스를 정의하는 클래스 정의의 /* TODO: put your data source class name here */ 주석을 데이터 모델의 엔터티 컨테이너인 형식(이 경우 NorthwindDataContext)으로 바꿉니다.

  5. 데이터 서비스 코드에서 InitializeService 함수의 자리 표시자 코드를 다음 코드로 바꿉니다.

    config.SetEntitySetAccessRule("Customers", EntitySetRights.ReadMultiple)
    config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead _
                                Or EntitySetRights.WriteMerge)
    config.SetEntitySetAccessRule("Order_Details", EntitySetRights.AllRead _
                                Or EntitySetRights.AllWrite)
    config.SetEntitySetAccessRule("Products", EntitySetRights.ReadMultiple)
    
    config.SetEntitySetAccessRule("Customers", EntitySetRights.ReadMultiple);
    config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead  
                                | EntitySetRights.WriteMerge);
    config.SetEntitySetAccessRule("Order_Details", EntitySetRights.AllRead                             
                                | EntitySetRights.AllWrite);
    config.SetEntitySetAccessRule("Products", EntitySetRights.ReadMultiple);
    

    이렇게 하면 권한 있는 클라이언트가 지정된 세 개 엔터티 집합의 리소스에 액세스할 수 있습니다.

  6. 웹 브라우저를 사용하여 Northwind.svc 데이터 서비스를 테스트하려면 웹 브라우저에서 서비스 액세스(WCF Data Services 퀵 스타트) 항목의 지침을 따릅니다.

참고 항목

작업

방법: ADO.NET Entity Framework 데이터 소스를 사용하여 데이터 서비스 만들기(WCF Data Services)
방법: 리플렉션 공급자를 사용하여 데이터 서비스 만들기(WCF Data Services)

개념

데이터 서비스 공급자(WCF Data Services)