Silverlight下用Ria Services访问多种数据库

  Ria Services 与 linq to Sql, Ado.net Entity Framework 的集合很紧密,但现目前不能支持其他数据库的操作(如:Oracle,my SQL等……),而现在支持多数据库的ORM: DataObjects.Net不错,对Linq的支持最完整的一个ORM了,但是现目前不支持.net framwork 4.0,官方好像正在支持中。。。看了很久,现目前还是只能用NHibernate了,FluentNHibernate为何物,大家可以去官方网站看看http://fluentnhibernate.org/

  

好,那么我们尝试用FluentNHibernate来实现Ria Service,多数据库访问。我们就用Oracle来做实验咯:)

添加一些dll

2010053019415129.jpg

首先来建立连接Session:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
private static ISessionFactory createSessionFactory()
{
FluentConfiguration fluentCfg
= Fluently.Configure()
.Database(
OracleDataClientConfiguration
.Oracle10
.ConnectionString(
c
=> c.Server(ConfigurationManager.AppSettings[ " DBHost " ]) // 127.0.0.1")
.Instance(ConfigurationManager.AppSettings[ " DBInstance " ])
.Username(ConfigurationManager.AppSettings[
" DBUser " ])
.Password(ConfigurationManager.AppSettings[
" DBPwd " ])
).QuerySubstitutions(
" true=1,false=0 " ))
.Mappings(m
=> m.FluentMappings.AddFromAssemblyOf < Department > ());

ISessionFactory factory
= null ;
try
{
factory
= fluentCfg.BuildSessionFactory();
}
catch (Exception ex)
{
log.Error(ex);
throw new Exception( " 创建数据库连接出错。 " ,ex);
}
return factory;
}

MS SQL 连接也很方便 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
FluentConfiguration fluentSqlCfg = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008.ConnectionString(
cn
=> cn.Server(ConfigurationManager.AppSettings[ " DBHost " ]) // 127.0.0.1")
.Database(ConfigurationManager.AppSettings[ " DBInstance " ])
.Username(ConfigurationManager.AppSettings[
" DBUser " ])
.Password(ConfigurationManager.AppSettings[
" DBPwd " ])
).QuerySubstitutions(
" true=1,false=0 " ))
.Mappings(m
=> m.FluentMappings.AddFromAssemblyOf < Department > ());

  

 

  好进入重点,接下来实验下服务器到客服端的元数据转换是怎么样的。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
public class Department
{
public int Id { get ; set ; }

public string Code { get ; set ; }

public string Name { get ; set ; }
}


[EnableClientAccess]
public class OrganizationService : DomainService
{
[Query]
public IQueryable < Department > GetAllDepartment()
{
return new List < Department > ().AsQueryable();
}

public void AddDepartment(Department depart)
{

}

public void UpdateDepartment(Department depart)
{

}

public void DeleteDepartment(Department department)
{

}
}

编译时会出错,提示为:2010053018110042.jpg

原来必须要生有一个KeyAttribute 的标记属性字段。我们加上后,成功了!所在的客户端会自动生成一堆文件代码:(请看下图)

2010053018154836.jpg

 

  我的的实体据模型肯定会有很多关联组合情况。我们扩展下:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
public class Department
{
[Key]
public int Id { get ; set ; }

public string Code { get ; set ; }

public string Name { get ; set ; }

public virtual Department Parent { get ; set ; }
}

public class Person
{
[Key]
public int Id { get ; set ; }

public string Login { get ; set ; }

public string Password { get ; set ; }

public String Code { get ; set ; }

public String Name { get ; set ; }

public Department Department { get ; set ; }

}

我们编译后看看客户端到底是什么:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// The 'Department' entity class.
/// </summary>
[DataContract(Namespace = " http://schemas.datacontract.org/2004/07/Platform.Web.Models " )]
public sealed partial class Department : Entity
{

private string _code;

private int _id;

private string _name;

#region Extensibility Method Definitions

/// <summary>
/// This method is invoked from the constructor once initialization is complete and
/// can be used for further object setup.
/// </summary>
partial void OnCreated();
partial void OnCodeChanging( string value);
partial void OnCodeChanged();
partial void OnIdChanging( int value);
partial void OnIdChanged();
partial void OnNameChanging( string value);
partial void OnNameChanged();

#endregion


/// <summary>
/// Initializes a new instance of the <see cref="Department"/> class.
/// </summary>
public Department()
{
this .OnCreated();
}

/// <summary>
/// Gets or sets the 'Code' value.
/// </summary>
[DataMember()]
public string Code
{
get
{
return this ._code;
}
set
{
if (( this ._code != value))
{
this .OnCodeChanging(value);
this .RaiseDataMemberChanging( " Code " );
this .ValidateProperty( " Code " , value);
this ._code = value;
this .RaiseDataMemberChanged( " Code " );
this .OnCodeChanged();
}
}
}

/// <summary>
/// Gets or sets the 'Id' value.
/// </summary>
[DataMember()]
[Editable(
false , AllowInitialValue = true )]
[Key()]
[RoundtripOriginal()]
public int Id
{
get
{
return this ._id;
}
set
{
if (( this ._id != value))
{
this .OnIdChanging(value);
this .ValidateProperty( " Id " , value);
this ._id = value;
this .RaisePropertyChanged( " Id " );
this .OnIdChanged();
}
}
}

/// <summary>
/// Gets or sets the 'Name' value.
/// </summary>
[DataMember()]
public string Name
{
get
{
return this ._name;
}
set
{
if (( this ._name != value))
{
this .OnNameChanging(value);
this .RaiseDataMemberChanging( " Name " );
this .ValidateProperty( " Name " , value);
this ._name = value;
this .RaiseDataMemberChanged( " Name " );
this .OnNameChanged();
}
}
}

/// <summary>
/// Computes a value from the key fields that uniquely identifies this entity instance.
/// </summary>
/// <returns> An object instance that uniquely identifies this entity instance. </returns>
public override object GetIdentity()
{
return this ._id;
}
}

/// <summary>
/// The 'Person' entity class.
/// </summary>
[DataContract(Namespace = " http://schemas.datacontract.org/2004/07/Platform.Web.Models " )]
public sealed partial class Person : Entity
{

private string _code;

private int _id;

private string _login;

private string _name;

private string _password;

#region Extensibility Method Definitions

/// <summary>
/// This method is invoked from the constructor once initialization is complete and
/// can be used for further object setup.
/// </summary>
partial void OnCreated();
partial void OnCodeChanging( string value);
partial void OnCodeChanged();
partial void OnIdChanging( int value);
partial void OnIdChanged();
partial void OnLoginChanging( string value);
partial void OnLoginChanged();
partial void OnNameChanging( string value);
partial void OnNameChanged();
partial void OnPasswordChanging( string value);
partial void OnPasswordChanged();

#endregion


/// <summary>
/// Initializes a new instance of the <see cref="Person"/> class.
/// </summary>
public Person()
{
this .OnCreated();
}

/// <summary>
/// Gets or sets the 'Code' value.
/// </summary>
[DataMember()]
public string Code
{
get
{
return this ._code;
}
set
{
if (( this ._code != value))
{
this .OnCodeChanging(value);
this .RaiseDataMemberChanging( " Code " );
this .ValidateProperty( " Code " , value);
this ._code = value;
this .RaiseDataMemberChanged( " Code " );
this .OnCodeChanged();
}
}
}

/// <summary>
/// Gets or sets the 'Id' value.
/// </summary>
[DataMember()]
[Editable(
false , AllowInitialValue = true )]
[Key()]
[RoundtripOriginal()]
public int Id
{
get
{
return this ._id;
}
set
{
if (( this ._id != value))
{
this .OnIdChanging(value);
this .ValidateProperty( " Id " , value);
this ._id = value;
this .RaisePropertyChanged( " Id " );
this .OnIdChanged();
}
}
}

/// <summary>
/// Gets or sets the 'Login' value.
/// </summary>
[DataMember()]
public string Login
{
get
{
return this ._login;
}
set
{
if (( this ._login != value))
{
this .OnLoginChanging(value);
this .RaiseDataMemberChanging( " Login " );
this .ValidateProperty( " Login " , value);
this ._login = value;
this .RaiseDataMemberChanged( " Login " );
this .OnLoginChanged();
}
}
}

/// <summary>
/// Gets or sets the 'Name' value.
/// </summary>
[DataMember()]
public string Name
{
get
{
return this ._name;
}
set
{
if (( this ._name != value))
{
this .OnNameChanging(value);
this .RaiseDataMemberChanging( " Name " );
this .ValidateProperty( " Name " , value);
this ._name = value;
this .RaiseDataMemberChanged( " Name " );
this .OnNameChanged();
}
}
}

/// <summary>
/// Gets or sets the 'Password' value.
/// </summary>
[DataMember()]
public string Password
{
get
{
return this ._password;
}
set
{
if (( this ._password != value))
{
this .OnPasswordChanging(value);
this .RaiseDataMemberChanging( " Password " );
this .ValidateProperty( " Password " , value);
this ._password = value;
this .RaiseDataMemberChanged( " Password " );
this .OnPasswordChanged();
}
}
}

/// <summary>
/// Computes a value from the key fields that uniquely identifies this entity instance.
/// </summary>
/// <returns> An object instance that uniquely identifies this entity instance. </returns>
public override object GetIdentity()
{
return this ._id;
}
}

客户端的Eitity模型好像少了关联类啊!!!怎么办,赶紧查资料吧。原来关联类需要加属性AssociationAttribute标记。。。加后编译也报错好需要添加一些字段,原来wcf Ria 从客户端传到服务器只传送是关联类实体Id值。好了,我们看看完整的结果吧:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
public class Department
{
[Key]
public virtual int Id { get ; set ; }

[Display(GroupName
= " 基本信息 " , Name = " 编码 " )]
public virtual string Code { get ; set ; }

[Display(GroupName
= " 基本信息 " , Name = " 部门名称 " )]
public virtual string Name { get ; set ; }

/// <summary>
/// 是否是外部单位
/// </summary>
public virtual bool IsExtUnits { get ; set ; }


public virtual int ParentId { get ; set ; }

private Department _Parent;
/// <summary>
/// 上级部门或单位
/// </summary>
[Association( " Department_Parent " , " ParentId " , " Id " , IsForeignKey = true )]
[Display(GroupName
= " 基本信息 " , Name = " 上级部门 " )]
[Include]
public virtual Department Parent
{
get
{
return _Parent;
}
set
{
ParentId
= value == null ? 0 : value.Id;
_Parent
= value;
}
}

/// <summary>
/// 下级部门或单位
/// </summary>
[Association( " Department_Parent " , " Id " , " ParentId " )]
public virtual IList < Department > Children { get ; set ; }

/// <summary>
/// 当前部门或单位的人员
/// </summary>
[Include]
[Association(
" Person_Department " , " Id " , " DepartmentId " )]
public virtual IList < Person > Persons { get ; set ; }
}

public class Person
{
[Key]
public virtual int Id { get ; set ; }

[Display(GroupName
= " 基本信息 " , Name = " 用户名 " )]
public virtual string Login { get ; set ; }

[Display(GroupName
= " 基本信息 " , Name = " 密码 " )]
public virtual string Password { get ; set ; }

[Display(GroupName
= " 基本信息 " , Name = " 工号 " )]
public virtual String Code { get ; set ; }

[Display(GroupName
= " 基本信息 " , Name = " 姓名 " )]
public virtual String Name { get ; set ; }

#region 所在单位

public virtual int DepartmentId
{
get ;
set ;
}

private Department _department;

[Include]
[Association(
" Person_Department " , " DepartmentId " , " Id " , IsForeignKey = true )]
[Display(GroupName
= " 基本信息 " , Name = " 部门 " )]
public virtual Department Department
{
get
{
return _department;
}
set
{
this ._department = value;
DepartmentId
= value == null ? 0 : value.Id;
}
}

#endregion
}

  大家看到实体属性都有了virtual来修饰的,因为用FluentNHibernate构建映射时需要。

 

 

 

  现在看来从客户端到服务器之间的问题解决了,接下来该处理怎么将实体模型保存到数据库的问题了。

用Flunent 来映射很方便,我们在实体类同目录下添加以下代码。我们就直接上代码了。

  

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
public DepartmentMap()
{
// 如果没有Id值 自动生成唯一Id
Id(x => x.Id).GeneratedBy.HiLo( " HIBERNATE_UNIQUE_KEY " , " NEXT_HI " , " 1000 " );
Map(x
=> x.Code);
Map(x
=> x.Name).Not.Nullable();
Map(x
=> x.IsExtUnits);

// 外键关联映射
References < Department > (x => x.Parent).Column( " Parent_Id " );

HasMany
< Department > (x => x.Children).AsList().LazyLoad().KeyColumn( " Parent_Id " ).Inverse();

// Department_Id 是在Person表里面的一个外键,
// .Inverse()这个方法可以确保主表保存后在保存子表
HasMany < Person > (x => x.Persons).KeyColumn( " Department_Id " ).AsBag().Inverse();
}


public class PersonMap : ClassMap < Person >
{
public PersonMap()
{
// 实体类对应数据库表名称
Table( " Person " );
Id(x
=> x.Id).GeneratedBy.HiLo( " HIBERNATE_UNIQUE_KEY " , " NEXT_HI " , " 1000 " );
Map(x
=> x.Code);
Map(x
=> x.Name);
Map(x
=> x.Login);
Map(x
=> x.Password);

// 外键 Department_Id在Person表里
References < Department > (x => x.Department).Column( " Department_Id " );
// HasOne<UserProfile>(x => x.Profile).Cascade.All().PropertyRef(y=>y.User);

}
}

 

 

就这么简单,完成了实体模型到数据库的映射关系。用起来很方便吧。。。。(不过还是没有DataObjects.Net 实体定义方便,直接用Attribute就可以了),接下来我们来实现public class OrganizationService : DomainService 。记住服务类一定要加[EnableClientAccess]标记。

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
[EnableClientAccess]
public class OrganizationService : DomainService
{
/// <summary>
/// 更新,插入都需要检查外接关联关系
/// </summary>
/// <param name="entity"></param>
internal static void EnsureFKValue(Object entity)
{
if (entity == null )
{
return ;
}
ISession session
= SessionHelper.GetSession();
if (session == null )
{
return ; // log
}

string entityName = entity.GetType().FullName;
// session.SessionFactory.GetClassMetadata
Type entityType = entity.GetType();
PropertyInfo[] properties
= entityType.GetProperties();
foreach (var p in properties)
{
object [] attributes = p.GetCustomAttributes( typeof (AssociationAttribute), true );
if (attributes == null || attributes.Length == 0 )
{
continue ;
}

AssociationAttribute asso
= attributes[ 0 ] as AssociationAttribute;
if (asso.IsForeignKey)
{
PropertyInfo fkProp
= entityType.GetProperty(asso.ThisKey);
if (fkProp == null )
{
continue ;
}
int ? fkId = fkProp.GetValue(entity, null ) as int ? ;
if ( ! fkId.HasValue || fkId.Value <= 0 )
{
continue ;
}

// 获取关联的对象
Object fkEntity = session.Get(p.PropertyType, fkId.Value);
if (fkEntity == null )
{
continue ; // ?
}
p.SetValue(entity, fkEntity,
null );
}
else
{
// ?

}
}
}

[Query]
public IQueryable < Department > GetDeparments()
{
var query
= SessionHelper.GetSession().Linq < Department > ();
return query;
}

public void AddDepartment(Department department)
{
var session
= SessionHelper.GetSession();
EnsureFKValue(department);
session.Save(department);
session.Flush();
}

public void UpdateDepartment(Department department)
{
var session
= SessionHelper.GetSession();
EnsureFKValue(department);
session.Update(department);
session.Flush();
}

public void DeleteDepartment(Department department)
{
var session
= SessionHelper.GetSession();
var item
= session.Linq < Department > ().FirstOrDefault(a => a.Id == department.Id);
if (item != null )
session.Delete(item);
session.Flush();
}


[Query]
public IQueryable < Person > GetAllPerson()
{
var query
= SessionHelper.GetSession().Linq < Person > ();
return query;
}

public void AddPerson(Person person)
{
var session
= SessionHelper.GetSession();
EnsureFKValue(person);
session.Save(person);
session.Flush();
}

public void UpdatePerson(Person person)
{
var session
= SessionHelper.GetSession();
EnsureFKValue(person);
session.Update(person);
session.Flush();
}

public void DeletePerson(Person person)
{
var session
= SessionHelper.GetSession();
var item
= session.Linq < Person > ().FirstOrDefault(a => a.Id == person.Id);
if (item != null )
session.Delete(item);
session.Flush();
}
}

到此我们就可以用wcf Ria Service 方式进行传输数据方式 实现对不同数据库的操作了。

写到这里,我想也有必要介绍下自定义用户验证,下一节我们再介绍吧,休息。。。

转载于:https://www.cnblogs.com/zhouhoujun/archive/2010/05/30/1747424.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值