Nhibernate学习起步之many-to-one篇

1.     学习目的:

通过进一步学习nhibernate基础知识,在实现单表CRUD的基础上,实现两表之间one-to-many的关系.

2.     开发环境+必要准备

开发环境: windows 2003,Visual studio .Net 2005,Sql server 2005 developer edition

必要准备: 学习上篇文章单表操作   

3. 对上篇文章中部分解释

 1)在User.hbm.xml中class节点中有一个lazy的属性,这个属性用于指定是否需要延迟加载(lazy loading),在官方文档中称为:lazy fecting.可以说延迟加载是nhibernate最好的特点,因为它可以在父类中透明的加载子类集合,这对于many-to-one的业务逻辑中,真是方便极了。但是有些时候,父类是不需要携带子类信息的。这时候如果也加载,无疑对性能是一种损失。在映射文件的class节点中可以通过配置lazy属性来指定是否支持延迟加载,这就更灵活多了。 

 2) 在User.hbm.xml中generate节点,代表的是主键的生成方式,上个例子中的”native”根据底层数据库的能力选择identity,hilo,sequence中的一个,比如在MS Sql中,使我们最经常使用的自动增长字段,每次加1. 

3) 在NHibernateHelper.cs中,创建Configuration对象的代码:new Configuration().Configure(@"E:\myproject\nhibernatestudy\simle1\NHibernateStudy1\NhibernateSample1\hibernate.cfg.xml");因为我是在单元测试中调试,所以将绝对路径的配置文件传递给构造函数。如果在windows app或者web app可以不用传递该参数。 

4. 实现步骤

 1)确定实现的业务需求:用户工资管理系统

 2) 打开上篇文章中的NHibernateStudy1解决方案。向项目NhibernateSample1添加类Salary;代码如下

ContractedBlock.gif ExpandedBlockStart.gif Salary.cs
None.gifusing 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 partial class Salary
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
int _id;
InBlock.gif        User _user;
InBlock.gif        
int _year;
InBlock.gif        
int _month;
InBlock.gif        
int _envy;
InBlock.gif        
decimal _money;
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        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 雇员
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public virtual User Employee
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _user;
ExpandedSubBlockEnd.gif            }

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

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 年度
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public int Year
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _year;
ExpandedSubBlockEnd.gif            }

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

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 月份
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public int Month
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _month;
ExpandedSubBlockEnd.gif            }

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

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 季度
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public int Envy
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _envy;
ExpandedSubBlockEnd.gif            }

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

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 工资
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public decimal Money
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return _money;
ExpandedSubBlockEnd.gif            }

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

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

3) 更改User.cs,在User里面添加SalaryList属性:

ContractedBlock.gif ExpandedBlockStart.gif User.cs
 1None.gifprivate System.Collections.IList _salaryList;
 2ExpandedBlockStart.gifContractedBlock.gif /**//// <summary>
 3InBlock.gif        /// 工资列表
 4ExpandedBlockEnd.gif        /// </summary>

 5None.gif        public System.Collections.IList SalaryList
 6ExpandedBlockStart.gifContractedBlock.gif        dot.gif{
 7InBlock.gif            get
 8ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 9InBlock.gif                return _salaryList;
10ExpandedSubBlockEnd.gif            }

11InBlock.gif            set
12ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
13InBlock.gif                _salaryList = value;
14ExpandedSubBlockEnd.gif            }

15ExpandedBlockEnd.gif        }
4)修改User.hbm.xml,加入bag节点
ContractedBlock.gif ExpandedBlockStart.gif User.hbm.xml
None.gif<bag name="SalaryList" table="Salary" inverse="true" lazy="true" cascade="all">
None.gif      
<key column="Id"/>
None.gif      
<one-to-many class="NhibernateSample1.Salary,NhibernateSample1"></one-to-many>
None.gif    
</bag>

 5 )编写类Salary的映射文件:Salary.hbm.xml
ContractedBlock.gif ExpandedBlockStart.gif Salary.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.Salary,NhibernateSample1" table="Salary" lazy="false">
None.gif    
<id name="Id" column="Id" unsaved-value="0">
None.gif      
<generator class="native" />
None.gif    
</id>
None.gif    
<property name="Year" column="Year" type="Int32" not-null="true"></property>
None.gif    
<property name="Month"  column="Month"  type="Int32" not-null="true"></property>
None.gif    
<property name="Envy"  column="Envy"  type="Int32" not-null="true"></property>
None.gif    
<property name="Money"  column="Money"  type="Decimal" not-null="true"></property>
None.gif    
<many-to-one name="Employee" column="Uid" not-null="true"></many-to-one>
None.gif  
</class>
None.gif
</hibernate-mapping>
6 )编写CRUD
ContractedBlock.gif ExpandedBlockStart.gif UserSalaryFixure.cs
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 UserSalaryFixure
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 User CreateUser(String name,string pwd)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            User u 
= new User();
InBlock.gif            u.Name 
= name;
InBlock.gif            u.Pwd 
= pwd;
InBlock.gif            u.SalaryList 
= new ArrayList();
InBlock.gif
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 Salary CreateSalary(User u, int year,int month,int envy,decimal money)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Salary item 
= new Salary();
InBlock.gif            item.Year 
= year;
InBlock.gif            item.Money 
= money;
InBlock.gif            item.Envy 
= envy;
InBlock.gif            item.Month 
= month;
InBlock.gif            item.Employee 
= u;
InBlock.gif            u.SalaryList.Add(item);
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.Update(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            
return item;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public Salary CreateSalary(int uid,int year, int month, int envy, decimal money)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Salary item 
= new Salary();
InBlock.gif            item.Year 
= year;
InBlock.gif            item.Money 
= money;
InBlock.gif            item.Envy 
= envy;
InBlock.gif            item.Month 
= month;
InBlock.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                User u 
= (User)session.Load(typeof(User), uid);
InBlock.gif                item.Employee 
= u;
InBlock.gif                u.SalaryList.Add(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            }

InBlock.gif            
return item;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public Salary GetSalary(int salaryID)
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                Salary item 
= (Salary)session.Load(typeof(Salary),
InBlock.gif                    salaryID);               
InBlock.gif                tx.Commit();
InBlock.gif                
return item;
ExpandedSubBlockEnd.gif            }

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

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

InBlock.gif            
return null;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public User GetUser(int uid)
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                User item 
= (User)session.Load(typeof(User),
InBlock.gif                    uid);
InBlock.gif                tx.Commit();
InBlock.gif                
return item;
ExpandedSubBlockEnd.gif            }

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

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

InBlock.gif            
return null;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public void UpdateSalary(int salaryID, decimal money)
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                Salary item 
= (Salary)session.Load(typeof(Salary),
InBlock.gif                    salaryID);
InBlock.gif                item.Money 
= money;
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
InBlock.gif        
public void Delete(int uid)
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                Salary item 
= session.Load(typeof(Salary), uid) as Salary; ;
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
7) 编写单元测试类:UnitTest1.cs
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.UserSalaryFixure usf 
= new UserSalaryFixure();
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            User u 
= usf.CreateUser(Guid.NewGuid().ToString(), "ds");
InBlock.gif            Assert.IsTrue(u.Id
>0);
InBlock.gif            Salary s 
= usf.CreateSalary(u, 200731, (decimal)8000.00);
InBlock.gif            Assert.IsTrue(s.Id 
> 0);
InBlock.gif            Salary s1 
= usf.CreateSalary(u.Id, 200731, (decimal)7500);
InBlock.gif            Assert.IsTrue(s1.Id
>0);
InBlock.gif            usf.UpdateSalary(s1.Id, (
decimal)6000);
InBlock.gif            s1 
= usf.GetSalary(s1.Id);
InBlock.gif            Assert.IsTrue(s1.Money 
== (decimal)6000);
InBlock.gif            usf.Delete(s1.Id);
InBlock.gif            s1 
= usf.GetSalary(s1.Id);
InBlock.gif            Assert.IsNull(s1);
InBlock.gif            User u1 
= usf.GetUser(1);
InBlock.gif            Assert.IsTrue(u1.SalaryList.Count
>0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
加载测试元数据,直到Test()通过。
总结:通过进一步学习nhiberate,发现ORM框架真是非常强大。今天先到这里。明天继续。
项目文件: /Files/jillzhang/simple2.rar

转载于:https://www.cnblogs.com/jillzhang/archive/2007/03/23/684567.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值