Skip to content

解决DataBase只有一个Read节点时,而且没有写weight属性,导致权重选择出异常的问题,同时在build xmlConfig时,强制验证Read节点是否写了Weight属性,当Read节点大于2时,其中一个read节点没有写weight属性,直接抛异常 #146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/SmartSql.Test.Unit/ConfigBuilder/XmlConfigLoaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using SmartSql.ConfigBuilder;
using SmartSql.Exceptions;
using Xunit;

namespace SmartSql.Test.Unit.ConfigBuilder
Expand All @@ -14,5 +15,18 @@ public void Load()
var configLoader = new XmlConfigBuilder(ResourceType.File, "SmartSqlMapConfig.xml");
var config = configLoader.Build();
}
[Fact]
public void LoadFailTest()
{
try
{
var configLoader = new XmlConfigBuilder(ResourceType.File, "SmartSqlMapConfig2.xml");
var config = configLoader.Build();
}
catch (SmartSqlException ex)
{
Assert.StartsWith( "Read Nodes must have Weight attribute",ex.Message);
}
}
}
}
3 changes: 3 additions & 0 deletions src/SmartSql.Test.Unit/SmartSql.Test.Unit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@
<None Update="Maps\T_Entity.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SmartSqlMapConfig2.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SmartSqlMapConfig.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down
2 changes: 1 addition & 1 deletion src/SmartSql.Test.Unit/SmartSqlMapConfig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<DbProvider Name="${DbProvider}"/>
<Write Name="WriteDB" ConnectionString="${ConnectionString}"/>
<Read Name="ReadDb-1" ConnectionString="${ConnectionString}" Weight="100"/>
<Read Name="ReadDb-2" ConnectionString="${ConnectionString}" Weight="100"/>
<Read Name="ReadDb-2" ConnectionString="${ConnectionString}" Weight="100" />
</Database>
<TypeHandlers>
<TypeHandler PropertyType="SmartSql.Test.Entities.UserInfo,SmartSql.Test" Type="${JsonTypeHandler`}">
Expand Down
99 changes: 99 additions & 0 deletions src/SmartSql.Test.Unit/SmartSqlMapConfig2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8" ?>
<SmartSqlMapConfig xmlns="http://SmartSql.net/schemas/SmartSqlMapConfig.xsd">
<Settings IgnoreParameterCase="false" ParameterPrefix="$" IsCacheEnabled="true" EnablePropertyChangedTrack="true"
IgnoreDbNull="true"/>
<Properties>
<!-- <Property Name="Redis" Value="localhost"/>-->
<Property Name="DbProvider" Value="MsSqlServer"/>
<Property Name="ConnectionString"
Value="Data Source=.;Initial Catalog=SmartSqlTestDB;Integrated Security=True"/>
<Property Name="JsonTypeHandler`" Value="SmartSql.TypeHandler.JsonTypeHandler`1,SmartSql.TypeHandler"/>
<Property Name="JsonTypeHandler" Value="SmartSql.TypeHandler.JsonTypeHandler,SmartSql.TypeHandler"/>
<Property Name="ScriptBuilder" Value="SmartSql.ScriptTag.ScriptBuilder,SmartSql.ScriptTag"/>
<Property Name="RedisCacheProvider" Value="SmartSql.Cache.Redis.RedisCacheProvider,SmartSql.Cache.Redis"/>
</Properties>
<AutoConverters>
<AutoConverter Name="NoneConverter">
<Tokenizer Name="None"/>
<Converter Name="None"/>
</AutoConverter>
<AutoConverter Name="Default" Default="true">
<Tokenizer Name="Default"/>
<Converter Name="Pascal"/>
</AutoConverter>
<AutoConverter Name="PascalConverter">
<Tokenizer Name="Default">
<Properties>
<Property Name="IgnorePrefix" Value=""/>
<Property Name="Delimiter" Value="_"/>
<Property Name="UppercaseSplit" Value="false"/>
</Properties>
</Tokenizer>
<Converter Name="Pascal"/>
</AutoConverter>
<AutoConverter Name="DelimiterConverter">
<Tokenizer Name="Default">
<Properties>
<Property Name="IgnorePrefix" Value="col_"/>
<Property Name="Delimiter" Value="_"/>
<Property Name="UppercaseSplit" Value="true"/>
</Properties>
</Tokenizer>
<Converter Name="Delimiter">
<Properties>
<Property Name="Prefix" Value="Col_"/>
<Property Name="Delimiter" Value="_"/>
<Property Name="Mode" Value="FirstUpper"/>
</Properties>
</Converter>
</AutoConverter>
</AutoConverters>
<Database>
<!-- MsSqlServer: Microsoft.Data.SqlClient , SqlServer: System.Data.SqlClinet -->
<DbProvider Name="${DbProvider}"/>
<Write Name="WriteDB" ConnectionString="${ConnectionString}"/>
<Read Name="ReadDb-1" ConnectionString="${ConnectionString}" Weight="100"/>
<Read Name="ReadDb-2" ConnectionString="${ConnectionString}" />
</Database>
<TypeHandlers>
<TypeHandler PropertyType="SmartSql.Test.Entities.UserInfo,SmartSql.Test" Type="${JsonTypeHandler`}">
<Properties>
<Property Name="DateFormat" Value="yyyy-MM-dd mm:ss"/>
<Property Name="NamingStrategy" Value="Camel"/>
</Properties>
</TypeHandler>
<TypeHandler Name="AnsiStringTypeHandler" Type="SmartSql.TypeHandlers.StringTypeHandler,SmartSql">
<Properties>
<Property Name="DbType" Value="AnsiString"/>
</Properties>
</TypeHandler>
<TypeHandler Name="AnsiStringFixedLengthTypeHandler" Type="SmartSql.TypeHandlers.StringTypeHandler,SmartSql">
<Properties>
<Property Name="DbType" Value="AnsiStringFixedLength"/>
</Properties>
</TypeHandler>
<TypeHandler Name="Json" Type="${JsonTypeHandler}"></TypeHandler>

</TypeHandlers>
<TagBuilders>
<TagBuilder Name="Script" Type="${ScriptBuilder}"/>
</TagBuilders>
<IdGenerators>
<IdGenerator Name="SnowflakeId" Type="SnowflakeId">
<Properties>
<Property Name="WorkerIdBits" Value="9"/>
<Property Name="WorkerId" Value="511"/>
<Property Name="Sequence" Value="14"/>
</Properties>
</IdGenerator>
<IdGenerator Name="DbSequence" Type="DbSequence">
<Properties>
<Property Name="Step" Value="10"/>
<Property Name="SequenceSql" Value="Select Next Value For IdSequence;"/>
</Properties>
</IdGenerator>
</IdGenerators>
<SmartSqlMaps>
<SmartSqlMap Path="Maps" Type="Directory"></SmartSqlMap>
</SmartSqlMaps>
</SmartSqlMapConfig>
78 changes: 43 additions & 35 deletions src/SmartSql/ConfigBuilder/XmlConfigBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class XmlConfigBuilder : AbstractConfigBuilder

private readonly IWordsConverterBuilder _wordsConverterBuilder = new WordsConverterBuilder();
private readonly ITokenizerBuilder _tokenizerBuilder = new TokenizerBuilder();

public XmlConfigBuilder(ResourceType resourceType, string resourcePath, ILoggerFactory loggerFactory = null)
{
_resourceType = resourceType;
Expand Down Expand Up @@ -153,12 +153,8 @@ protected override void BuildDatabase()
database.Write.DbProvider = database.DbProvider;
var readDataSourceNodes = databaseNode.SelectNodes($"{CONFIG_PREFIX}:Read", XmlNsManager);
if (readDataSourceNodes == null) return;
foreach (XmlNode readNode in readDataSourceNodes)
{
var readDb = ParseReadDataSource(readNode);
readDb.DbProvider = database.DbProvider;
database.Reads.Add(readDb.Name, readDb);
}
var readDataSources = this.ParseReadDataSource(readDataSourceNodes, database.DbProvider);
database.Reads.AddRange(readDataSources);
}

private DbProvider ParseDbProvider(XmlNode dbProviderNode)
Expand Down Expand Up @@ -226,34 +222,46 @@ private WriteDataSource ParseWriteDataSource(XmlNode writeDataSourceNode)
{
writeDataSource.ConnectionString = connectionString;
}

return writeDataSource;
}
private ReadDataSource ParseReadDataSource(XmlNode readDataSourceNode)
private IDictionary<string, ReadDataSource> ParseReadDataSource(XmlNodeList readDataSourceNodes, DbProvider dbProvider)
{
if (readDataSourceNode == null)
{
throw new SmartSqlException("ReadDataSource can not be null.");
}
var readDataSource = new ReadDataSource();
if (readDataSourceNode.Attributes.TryGetValueAsString(nameof(ReadDataSource.Name), out string name, SmartSqlConfig.Properties)
)
{
readDataSource.Name = name;
}
if (readDataSourceNode.Attributes.TryGetValueAsString(nameof(ReadDataSource.ConnectionString), out string connectionString, SmartSqlConfig.Properties)
)
{
readDataSource.ConnectionString = connectionString;
}
if (readDataSourceNode.Attributes.TryGetValueAsInt32(nameof(ReadDataSource.Weight), out int weight, SmartSqlConfig.Properties)
)
{
readDataSource.Weight = weight;
var readDataSources = new Dictionary<string, ReadDataSource>();
var s = new List<string>();
foreach (XmlNode readDataSourceNode in readDataSourceNodes)
{

var readDataSource = new ReadDataSource();
if (readDataSourceNode.Attributes.TryGetValueAsString(nameof(ReadDataSource.Name), out string name, SmartSqlConfig.Properties) )
{
readDataSource.Name = name;
}
else
{
throw new SmartSqlException($"Read Nodes must have Name attribute");
}
if (readDataSourceNode.Attributes.TryGetValueAsString(nameof(ReadDataSource.ConnectionString), out string connectionString, SmartSqlConfig.Properties) )
{
readDataSource.ConnectionString = connectionString;
}
if (readDataSourceNode.Attributes.TryGetValueAsInt32(nameof(ReadDataSource.Weight), out int weight, SmartSqlConfig.Properties) )
{
readDataSource.Weight = weight;
}
else
{
if (readDataSourceNodes.Count > 1)
{
throw new SmartSqlException($"Read Nodes must have Weight attribute,Name is {readDataSource.Name}");
}
}
readDataSource.DbProvider = dbProvider;
readDataSources.Add(readDataSource.Name, readDataSource);
}

return readDataSource;
return readDataSources;
}

#endregion
#region 3. TypeHandlers
protected override void BuildTypeHandlers()
Expand Down Expand Up @@ -414,7 +422,7 @@ private void BuildAutoConverter(XmlNode autoConverterNode)
var wordsConverter = BuildWordsConverter(wordsConverterNode);

var autoConverter = new AutoConverter.AutoConverter(converterName, tokenizer, wordsConverter);

SmartSqlConfig.AutoConverters.Add(autoConverter.Name, autoConverter);
if (isDefault)
{
Expand All @@ -431,7 +439,7 @@ private ITokenizer BuildTokenizer(XmlNode tokenizerNode)
var properties = ParseProperties(tokenizerNode);
return _tokenizerBuilder.Build(tokenizerName, properties);
}

private IWordsConverter BuildWordsConverter(XmlNode wordsConverterNode)
{
if (!wordsConverterNode.Attributes.TryGetValueAsString("Name", out String wordsConverterName, SmartSqlConfig.Properties))
Expand All @@ -441,10 +449,10 @@ private IWordsConverter BuildWordsConverter(XmlNode wordsConverterNode)
var properties = ParseProperties(wordsConverterNode);
return _wordsConverterBuilder.Build(wordsConverterName, properties);
}

#endregion


private IDictionary<String, object> ParseProperties(XmlNode parentNode)
{
var parametersNode = parentNode.SelectSingleNode($"{CONFIG_PREFIX}:Properties", XmlNsManager);
Expand Down
7 changes: 7 additions & 0 deletions src/SmartSql/Utils/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ public static void EnsureValue<TKey, TValue, TTypedValue>(this IDictionary<TKey,
throw new SmartSqlException($"Can not find Parameter:{key}!");
}
}
public static void AddRange<TKey, TValue>(this IDictionary<TKey,TValue> dic, IDictionary<TKey,TValue> collection)
{
foreach(var item in collection)
{
dic.Add(item);
}
}

}
}
12 changes: 11 additions & 1 deletion src/SmartSql/Utils/WeightFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace SmartSql.Utils
/// </summary>
public class WeightFilter<T>
{

/// <summary>
/// 选举权重源
/// </summary>
Expand All @@ -20,7 +21,16 @@ public WeightSource Elect(IEnumerable<WeightSource> inWeightSources)
{
var random = new Random((int)Stopwatch.GetTimestamp());
var weightSources = inWeightSources.ToList();
int totalWeight = weightSources.Sum(source => source.Weight);
int totalWeight = 0;
if (weightSources.Count ==1)
{
return weightSources[0];
}
else
{
totalWeight=weightSources.Sum(source => source.Weight);
}

int position = random.Next(1, totalWeight);
return FindByPosition(weightSources, position);
}
Expand Down