nhibernate学习之三级联(Ternary Associations)篇

    园子里面的兄弟们好,由于工作和身体的原因,几天来都没有写有关nhibernate学习系列了。看了看前几篇大家的回复,首先想要多谢兄弟们对小弟的关注和支持,可小弟水平有限,写出来的也只是入门级的心得。只是有一个心愿,那就是抛砖引玉,希望能和大家更多更好的互动。技术无极限,而我更想要得是能在园子里面认识更多的兄弟,更多的朋友。对了,忘记了一点事情,那就是,兄弟们,节日快乐,哈哈哈。。。唧唧歪歪这么多,大家不要见笑,下面进入正题
1) 学习目标
通过进一步学习Nhibernate基础知识,掌握用Nhiberate实现对级联的支持,通过一个简单的用户角色权限系统来体验nhibernate对级联的强大支持。
 
2)开发环境和必要准备 
  开发环境为:windows 2003,Visual studio .Net 2005,Sql server 2005 developer edition
  必要准备:学习前三篇nhibernate学习系列 Nhibernate学习之起步篇-1  , Nhibernate学习起步之many-to-one篇 , Nhibernate学习之many-to-many篇

3)示例
  业务需求:实现一个用户角色权限系统,一个用户只有一个角色,一个角色下有多个用户,一个角色下有多个权限,一个权限也对应多个角色
                      要求: (1).创建一个角色 (2)在该角色上创建两个个用户3)创建两个权限4)指定该角色上的权限列表5)获得一个用户的权限列表
  首先看关系数据库关系图:
  
4)实现步骤:
  1.User.cs
None.gif using  System;
None.gif
using  System.Collections.Generic;
None.gif
using  System.Text;
None.gif
None.gif
namespace  NhibernateSample1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public class User
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private int _id;
InBlock.gif        
private string _name;
InBlock.gif        
private string _pwd;
InBlock.gif        
private Role _role;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 编号
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public virtual int Id
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _id;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _id 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 名称
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public virtual string Name
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _name;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _name 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 密码
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public virtual string Pwd
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _pwd;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _pwd 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public virtual Role Role
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _role;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _role 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
 User.hbm.xml
None.gif <? xml version = " 1.0 "  encoding = " utf-8 "   ?>
None.gif
< hibernate - mapping xmlns = " urn:nhibernate-mapping-2.2 " >
None.gif  
< class  name = " NhibernateSample1.User,NhibernateSample1 "  table = " Users "  lazy = " false " >
None.gif    
< id name = " Id "  column = " Id "  unsaved - value = " 0 " >
None.gif      
< generator  class = " native "   />
None.gif    
</ id >
None.gif    
< property name = " Name "  column = " Name "  type = " string "  length = " 64 "  not - null = " true "  unique = " true " ></ property >
None.gif    
< property name = " Pwd "   column = " Pwd "   type = " string "  length = " 64 "  not - null = " true " ></ property >
None.gif    
< many - to - one name = " Role "    class = " NhibernateSample1.Role,NhibernateSample1 "  column = " RoleID " ></ many - to - one >
None.gif   
</ class >
None.gif
</ hibernate - mapping >
2.Role.cs
None.gif using  System;
None.gif
using  System.Collections.Generic;
None.gif
using  System.Text;
None.gif
using  System.Collections;
None.gif
None.gif
namespace  NhibernateSample1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public class Role
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
int _roleID;
InBlock.gif        
string _roleName;
InBlock.gif        IList _list 
= new  ArrayList();
InBlock.gif        IList _permissionList 
= new ArrayList();
InBlock.gif        
public virtual IList PermissionList
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _permissionList;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _permissionList 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public virtual int RoleID
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _roleID;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _roleID 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public virtual IList UserList
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _list;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _list 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public virtual string RoleName
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _roleName;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _roleName 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
Role.hbm.xml
None.gif <? xml version = " 1.0 "  encoding = " utf-8 "   ?>
None.gif
< hibernate - mapping xmlns = " urn:nhibernate-mapping-2.2 " >
None.gif  
< class  name = " NhibernateSample1.Role,NhibernateSample1 "  table = " Roles "  lazy = " false " >
None.gif    
< id name = " RoleID "  column = " RoleID "  unsaved - value = " 0 " >
None.gif      
< generator  class = " native "   />
None.gif    
</ id >
None.gif    
< property name = " RoleName "   column = " RoleName "   type = " string "  length = " 64 "  not - null = " true " ></ property >
None.gif    
< bag name = " PermissionList "  table = " Role_Permissions "  inverse = " true "  lazy = " false "  cascade = " all " >
None.gif      
< key column = " RoleID " />
None.gif      
< many - to - many  class = " NhibernateSample1.Permission,NhibernateSample1 "  column = " PermissionID " ></ many - to - many >
None.gif    
</ bag >
None.gif    
< bag name = " UserList "  table = " Users "  inverse = " true "  lazy = " false "  cascade = " all " >
None.gif      
< key column = " RoleID " />
None.gif      
< one - to - many  class = " NhibernateSample1.User,NhibernateSample1 " ></ one - to - many >
None.gif    
</ bag >
None.gif  
</ class >
None.gif
</ hibernate - mapping >
3.Permission.cs
None.gif using  System;
None.gif
using  System.Collections.Generic;
None.gif
using  System.Text;
None.gif
using  System.Collections;
None.gif
None.gif
namespace  NhibernateSample1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public class Permission
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
int _permissionID;
InBlock.gif        
string _permissionName;
InBlock.gif        IList _roleList 
= new ArrayList();
InBlock.gif        
public virtual int PermissionID
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _permissionID;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _permissionID 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public virtual string PermissionName
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _permissionName;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _permissionName
=value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public virtual IList RoleList
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _roleList;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                _roleList 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
Permission.hbm.xml
None.gif <? xml version = " 1.0 "  encoding = " utf-8 "   ?>
None.gif
< hibernate - mapping xmlns = " urn:nhibernate-mapping-2.2 " >
None.gif  
< class  name = " NhibernateSample1.Permission,NhibernateSample1 "  table = " Permissions "  lazy = " false " >
None.gif    
< id name = " PermissionID "  column = " PermissionID "  unsaved - value = " 0 " >
None.gif      
< generator  class = " native "   />
None.gif    
</ id >
None.gif    
< property name = " PermissionName "  column = " PermissionName "  type = " string "  length = " 64 "  not - null = " true "  unique = " true " ></ property >
None.gif    
< bag name = " RoleList "  table = " Role_Permissions "   lazy = " true " >
None.gif      
< key column = " PermissionID " />
None.gif      
< many - to - many  class = " NhibernateSample1.Role,NhibernateSample1 "  column = " RoleID " ></ many - to - many >
None.gif    
</ bag >
None.gif  
</ class >
None.gif
</ hibernate - mapping >
4。数据操作类
ContractedBlock.gif ExpandedBlockStart.gif UserRolePermissionFixure
None.gifusing System;
None.gif
using System.Collections.Generic;
None.gif
using System.Text;
None.gif
using System.Collections;
None.gif
using NHibernate;
None.gif
using NHibernate.Cfg;
None.gif
using NHibernate.Tool.hbm2ddl;
None.gif
None.gif
namespace NhibernateSample1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public  class UserRolePermissionFixure
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private ISessionFactory _sessions; 
InBlock.gif        
public void Configure()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Configuration cfg 
= GetConfiguration();      
InBlock.gif            _sessions 
= cfg.BuildSessionFactory();
ExpandedSubBlockEnd.gif        }

InBlock.gif        Configuration GetConfiguration()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
string cfgPath = @"E:\my project\nhibernate study\simle 1\NHibernateStudy1\NhibernateSample1\hibernate.cfg.xml";
InBlock.gif            Configuration cfg 
= new Configuration().Configure(cfgPath);
InBlock.gif            
return cfg;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public void ExportTables()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Configuration cfg 
= GetConfiguration();           
InBlock.gif            
new SchemaExport(cfg).Create(truetrue);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public Role CreateRole(string roleName)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Role r 
= new Role();
InBlock.gif            r.RoleName 
= roleName;
InBlock.gif            ISession session 
= _sessions.OpenSession();            
InBlock.gif            ITransaction tx 
= null;
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                tx 
= session.BeginTransaction();
InBlock.gif                session.Save(r);
InBlock.gif                tx.Commit();
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch(Exception e)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if (tx != null) tx.Rollback();
InBlock.gif                
throw e;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                session.Close();
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return r;
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public User CreateUser(String name,string pwd,Role r)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            User u 
= new User();
InBlock.gif            u.Name 
= name;
InBlock.gif            u.Pwd 
= pwd;
InBlock.gif            u.Role 
= r;
InBlock.gif            
//r.UserList.Add(u);
InBlock.gif
            ISession session = _sessions.OpenSession();
InBlock.gif
InBlock.gif            ITransaction tx 
= null;
InBlock.gif
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                tx 
= session.BeginTransaction();
InBlock.gif                session.Save(u);
InBlock.gif                tx.Commit();
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch (HibernateException e)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if (tx != null) tx.Rollback();
InBlock.gif                
throw e;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                session.Close();
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return u;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public Permission CreatePermission(Role r,string name)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Permission p 
= new Permission();
InBlock.gif            p.PermissionName 
= name;
InBlock.gif            r.PermissionList.Add(p);
InBlock.gif            p.RoleList.Add(r);
InBlock.gif            ISession session 
= _sessions.OpenSession();
InBlock.gif            ITransaction tx 
= null;
InBlock.gif
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                tx 
= session.BeginTransaction();
InBlock.gif                session.Save(p);
InBlock.gif                tx.Commit();
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch (HibernateException e)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if (tx != null) tx.Rollback();
InBlock.gif                
throw e;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                session.Close();
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return p;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public void DeleteRole(int rid)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            ISession session 
= _sessions.OpenSession();
InBlock.gif            ITransaction tx 
= null;
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                tx 
= session.BeginTransaction();
InBlock.gif                Role item 
= session.Load(typeof(Role), rid) as Role;
InBlock.gif                session.Delete(item);
InBlock.gif                tx.Commit();
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch (HibernateException e)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if (tx != null) tx.Rollback();
InBlock.gif                
throw e;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                session.Close();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
5。单元测试类
ContractedBlock.gif ExpandedBlockStart.gif UnitTest1.cs
None.gifusing System;
None.gif
using System.Text;
None.gif
using System.Collections.Generic;
None.gif
using Microsoft.VisualStudio.TestTools.UnitTesting;
None.gif
using NhibernateSample1;
None.gif
None.gif
namespace TestProject1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// UnitTest1 的摘要说明
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    [TestClass]
InBlock.gif    
public class UnitTest1
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
public UnitTest1()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// TODO: 在此处添加构造函数逻辑
InBlock.gif            
//
ExpandedSubBlockEnd.gif
        }

InBlock.gif        NhibernateSample1.UserRolePermissionFixure usf 
= new UserRolePermissionFixure();
ContractedSubBlock.gifExpandedSubBlockStart.gif        
其他测试属性#region 其他测试属性
InBlock.gif        
//
InBlock.gif        
// 您可以在编写测试时使用下列其他属性:
InBlock.gif        
//
InBlock.gif        
// 在运行类中的第一个测试之前使用 ClassInitialize 运行代码
InBlock.gif        
// [ClassInitialize()]
InBlock.gif        
// public static void MyClassInitialize(TestContext testContext) { }
InBlock.gif        
//
InBlock.gif        
// 在类中的所有测试都已运行之后使用 ClassCleanup 运行代码
InBlock.gif        
// [ClassCleanup()]
InBlock.gif        
// public static void MyClassCleanup() { }
InBlock.gif        
//
InBlock.gif        
// 在运行每个测试之前使用 TestInitialize 运行代码 
InBlock.gif        
// [TestInitialize()]
InBlock.gif        
// public void MyTestInitialize() { }
InBlock.gif        
//
InBlock.gif        
// 在运行每个测试之后使用 TestCleanup 运行代码
InBlock.gif        
// [TestCleanup()]
InBlock.gif        
// public void MyTestCleanup() { }
InBlock.gif        
//
ExpandedSubBlockEnd.gif
        #endregion

InBlock.gif
InBlock.gif        [TestMethod]
InBlock.gif        
public void Test1()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            usf.Configure();
InBlock.gif            usf.ExportTables();
InBlock.gif            Role r 
= usf.CreateRole("test");
InBlock.gif            Assert.IsTrue(r.RoleID 
> 0);
InBlock.gif            User u 
= usf.CreateUser(Guid.NewGuid().ToString(), "ds", r);            
InBlock.gif            Assert.IsTrue(u.Id 
> 0);
InBlock.gif            Permission p 
= usf.CreatePermission(r, "查询");
InBlock.gif            Assert.IsTrue(p.PermissionID 
> 0);         
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
   通过本篇的学习,将充分理解到nhibernate对级联支持的强大。另外除了支持三级联之外,他还支持异类关联(Heterogeneous Associations) .给开发带来了更多的灵活性和实用性。而且考虑到性能的问题,还添加了lazy这样的延迟加载的功能,加载父亲不必要一定要加载他的儿子集合。通过集合类映射,nhinernate轻松实现级联,这相比较代码生成来说,无疑是一个优点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值