/// <summary>
/// 會把物件 Parameter 的各 Property 帶入 SQL 中.
/// </summary>
/// <param name="dbct"></param>
/// <param name="sql"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static async Task<int> ExecuteParameterSqlAsync(this DbContext dbct, string sql, object parameters)
{
return await dbct.Database.ExecuteSqlRawAsync(sql, parameters.ToSqlParamsArray());
}
public async Task<object> EfTest()
{
var dbct = Ds.NewContext.GvContext;
var insertSql = @"Insert into ProfileEvent(JobId,[Name],GvShoplineId,LiShoplineId,Phone,Email,LineId,GaClientId)
Values(@JobId, @Name, null , null , null , @Email, @GaClientId , @GaClientId )";
//執行 SQL 的原生寫法
await dbct.Database.ExecuteSqlRawAsync(insertSql, new object[]
{
new SqlParameter("@JobId", 10),
new SqlParameter("@Email", "XX'TT"),
new SqlParameter("@Name", "AA'BB"),
new SqlParameter("@GaClientId", "GaClientId"),
});
//執行 SQL 的擴充寫法
await dbct.ExecuteParameterSqlAsync(insertSql, new
{
JobId = 10,
Email = "XX'TT",
Name = "AA'BB",
GaClientId = "GaClientId"
});
//關於查詢
string name = "%'B%";
//原生寫法
var res1 = await dbct.ProfileEvents.FromSqlRaw("Select top 100 * from ProfileEvent where Name like @name",
new object[]
{
new SqlParameter("@name", "%'B%")
})
.ToListAsync();
//擴充, object to SqlParameter array
var res2 = await dbct.ProfileEvents.FromSqlRaw("Select top 100 * from ProfileEvent where Name like @name",
new { name }.ToSqlParamsArray())
.ToListAsync();
var res3 = await dbct.ProfileEvents.FromSql($"Select top 100 * from ProfileEvent where Name like {name}")
.ToListAsync();
var res4 = await dbct.ProfileEvents.FromSqlInterpolated($"Select top 100 * from ProfileEvent where Name like {name}")
.ToListAsync();
return new { res1, res2, res3, res4 };
}
<ItemGroup>
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
<PackageReference Include="SQLiteNetExtensions.Async" Version="2.1.0" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.4" />
<PackageReference Include="SQLitePCLRaw.core" Version="2.1.4" />
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" Version="2.1.4" />
<PackageReference Include="SQLitePCLRaw.provider.dynamic_cdecl" Version="2.1.4" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup>
static List<Brush> CaptchaBrushes = null;
public static FileStreamResult CreateCaptcha(string captcha)
{
if (CaptchaBrushes == null)
{
CaptchaBrushes = new List<Brush>();
CaptchaBrushes.Add(Brushes.White);
CaptchaBrushes.Add(Brushes.Gold);
CaptchaBrushes.Add(Brushes.LightSkyBlue);
CaptchaBrushes.Add(Brushes.LimeGreen);
CaptchaBrushes.Add(Brushes.AliceBlue);
CaptchaBrushes.Add(Brushes.AntiqueWhite);
CaptchaBrushes.Add(Brushes.BurlyWood);
CaptchaBrushes.Add(Brushes.Silver);
}
int width = 90;
int height = 45;
//https://stackoverflow.com/questions/61365732/cannot-access-a-closed-stream-when-returning-filestreamresult-from-c-sharp-netc
//Using statements close and unload the variable from memory set in the using statement which is why you are getting an error trying to access a closed memory stream.You don't need to use a using statement if you are just going to return the result at the end.
//這個 memory stream 不用關閉或 dispose
var ms = new MemoryStream();
// 釋放所有在 GDI+ 所佔用的記憶體空間 ( 非常重要!! )
using (Bitmap _bmp = new Bitmap(width, height))
using (Graphics _graphics = Graphics.FromImage(_bmp))
using (Font _font = new Font("Courier New", 24, FontStyle.Bold)) // _font 設定要出現在圖片上的文字字型、大小與樣式
{
// (封裝 GDI+ 繪圖介面) 所有繪圖作業都需透過 Graphics 物件進行操作
_graphics.Clear(Color.Black);
// 如果想啟用「反鋸齒」功能,可以將以下這行取消註解
//_graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
// 將亂碼字串「繪製」到之前產生的 Graphics 「繪圖板」上
var x = 10;
for(var i = 0; i < captcha.Length; i++)
{
_graphics.DrawString(captcha.Substring(i, 1), _font, CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], x, Su.MathUtil.GetRandomInt(15));
x += 10 + Su.MathUtil.GetRandomInt(10);
}
// 畫線
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
Su.MathUtil.GetRandomInt(0, Convert.ToInt32((width * 0.9 / 2))), 0, Su.MathUtil.GetRandomInt(Convert.ToInt32(width / 2), Convert.ToInt32(width * 1.9 / 2)), height);
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
Su.MathUtil.GetRandomInt(Convert.ToInt32(width / 2), Convert.ToInt32(width * 1.9 / 2)), 0, Su.MathUtil.GetRandomInt(0, Convert.ToInt32((width * 0.9 / 2))), height);
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
0,
Su.MathUtil.GetRandomInt(height / 2),
width,
height / 2 + Su.MathUtil.GetRandomInt(height / 2)
);
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
0,
height / 2 + Su.MathUtil.GetRandomInt(height / 2),
width,
Su.MathUtil.GetRandomInt(height / 2)
);
_bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
}
ms.Seek(0, SeekOrigin.Begin);
// Controller 的型別為 FileResult
return new FileStreamResult(ms, "image/jpeg")
{ FileDownloadName = $"{DateTime.Now.Ymdhmsf()}.jpg" };
}
namespace Web.Controllers
{
public class CaptchaController : Controller
{
[Route("captcha")]
public async Task<FileStreamResult> Index()
{
//產生 Captcha 並存入 Session 之中。目前是四位數字
string captcha = (await Ah.ReGetAsync<object>("api/kol/create-captcha-code")).ToString();
//產生圖檔並回傳 FileStreamResult
return Su.Wu.CreateCaptcha(captcha);
}
}
}
var newFilename = filename.Replace("..", "").ValidFilenameCharacters();
int tries = 0;
while (tries < Su.PgSql.maxTransactionAborted)
{
try
{
using (var scop = new System.Transactions.TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var context = ShopBandContext.Context;
updateCount = await context.UpdateAsync<MarketDiscount>(dto, Sc.ModifyInfo,
onlyColumns: "StartAt,EndAt,NewPrice,FrontEndMemo,BackEndMemo");
scop.Complete();
break; //這個 Break 很重要
}
}
catch (Exception ex)
{
// 我發現因為是非同步模式,所以要檢查很多層的 InnerException
if (tries < Su.PgSql.maxTransactionAborted
&& ((ex.InnerException != null && ex.InnerException is Npgsql.PostgresException && ((Npgsql.PostgresException)ex.InnerException).SqlState == "40001")
|| (ex.InnerException.InnerException != null && ex.InnerException.InnerException is Npgsql.PostgresException && ((Npgsql.PostgresException)ex.InnerException.InnerException).SqlState == "40001")))
{
//隨機休息 10 ~ 20 ms, 等另一個 job 完工
System.Threading.Thread.Sleep(Su.MathUtil.Random.Next(10, 20));
tries++;
}
else
{
throw;
}
}
}
var combineBody = Expression.AndAlso(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
var finalExpression = Expression.Lambda<Func<TestClass, bool>>(combineBody, e1.Parameters).Compile();
public static class ExpressionExtension
{
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> e1, Expression<Func<T, bool>> e2)
{
var combineE = Expression.AndAlso(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
return Expression.Lambda<Func<T, bool>>(combineE, e1.Parameters);
}
public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> e1, Expression<Func<T, bool>> e2)
{
var combineE = Expression.OrElse(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
return Expression.Lambda<Func<T, bool>>(combineE, e1.Parameters);
}
}
Expression<Func<Market, bool>> e1 = e => e.Is_Deleted == isDelete;
Expression<Func<Market, bool>> e2 = e => string.IsNullOrEmpty(marketNo) || e.MarketNo.ToUpper().Contains(marketNo.ToUpper());
return new
{
andMarkets = Ds.PageContext.ShopBandContext.Markets.Where(e1.AndAlso(e2)).ToList(),
orMarkets = Ds.PageContext.ShopBandContext.Markets.Where(e1.OrElse(e2)).ToList(),
};
public static Expression<Func<T, bool>> OrElseAll<T>(this IEnumerable<Expression<Func<T, bool>>> exps)
{
if (exps.Count() == 1)
{
return exps.First();
}
var e0 = exps.First();
var orExp = exps.Skip(1).Aggregate(e0.Body, (x, y) => Expression.OrElse(x, Expression.Invoke(y, e0.Parameters[0])));
return Expression.Lambda<Func<T, bool>>(orExp, e0.Parameters);
}
public static Expression<Func<T, bool>> AndAlsoAll<T>(this IEnumerable<Expression<Func<T, bool>>> exps)
{
if (exps.Count() == 1)
{
return exps.First();
}
var e0 = exps.First();
var orExp = exps.Skip(1).Aggregate(e0.Body, (x, y) => Expression.AndAlso(x, Expression.Invoke(y, e0.Parameters[0])));
return Expression.Lambda<Func<T, bool>>(orExp, e0.Parameters);
}
Expression<Func<Market, bool>> q = e =>
e.Is_Deleted == "N"
&& (string.IsNullOrEmpty(marketNo) || e.MarketNo.ToLower().Contains(marketNo.ToLower()))
&& (string.IsNullOrEmpty(isCombination) || isCombination != "Y" || e.TypeEnum == 200);
if (!string.IsNullOrEmpty(name))
{
var nameList = name.Split(',').Select(e => e.Trim())
.Where(e => !string.IsNullOrEmpty(e));
if (nameList.Any())
{
q = q.AndAlso(nameList
.Select(s => (Expression<Func<Market, bool>>)(e => e.Name.ToLower().Contains(s.ToLower())))
.OrElseAll());
}
}
internal class MergeTool : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
protected override Expression VisitParameter(ParameterExpression node)
{
return base.VisitParameter(_parameter);
}
internal MergeTool(ParameterExpression parameter)
{
_parameter = parameter;
}
public static Expression<Func<T, bool>> MergedExpression<T>(Expression<Func<T, bool>> e1, Expression<Func<T, bool>> e2)
{
ParameterExpression param = Expression.Parameter(typeof(T));
BinaryExpression MergeBody = Expression.AndAlso(e1.Body, e2.Body);
var ReplacedBody = (BinaryExpression)new MergeTool(param).Visit(MergeBody);
return Expression.Lambda<Func<T, bool>>(ReplacedBody, param);
}
}
使用時要 Compile
var mergedExpression = MergeTool.MergedExpression(e1, e2);
var list = testList.Where(mergedExpression.Compile());
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
var _dir = new DirectoryInfo("LuceneDocument");
if (!File.Exists(_dir.FullName))
{
System.IO.Directory.CreateDirectory(_dir.FullName);
}
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_CURRENT);
CreateIndex(GetProductsInformation(), _dir, analyzer);
while (true)
{
Console.Write("請輸入欲查詢字串 :");
var searchValue = Console.ReadLine();
Search(searchValue, _dir, analyzer);
}
void CreateIndex(List<Product> information, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(dir))
{
using (var indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED))
{
foreach (var index in information)
{
var document = new Document();
document.Add(new Field("Id", index.Id.ToString(), Field.Store.YES, Field.Index.NO));
document.Add(new Field("Name", index.Name, Field.Store.YES, Field.Index.ANALYZED));
document.Add(new Field("Description", index.Description, Field.Store.YES, Field.Index.ANALYZED));
indexWriter.AddDocument(document);
}
indexWriter.Optimize();
indexWriter.Commit();
}
}
}
void Search(string searchValue, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(_dir))
{
var parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_CURRENT, "Description", analyzer).Parse(searchValue);
using (var indexSearcher = new IndexSearcher(directory))
{
var queryLimit = 20;
var hits = indexSearcher.Search(parser, queryLimit);
if (!hits.ScoreDocs.Any())
{
Console.WriteLine("查無相關結果。");
return;
}
Document doc;
foreach (var hit in hits.ScoreDocs)
{
doc = indexSearcher.Doc(hit.Doc);
Console.WriteLine("Score :" + hit.Score + ", Id :" + doc.Get("Id") + ", Name :" + doc.Get("Name") + ", Description :" + doc.Get("Description"));
}
}
}
}
List<Product> GetProductsInformation()
{
return new List<Product> {
new Product{ Id = 1, Name = "蘋果", Description = "一天一蘋果,醫生遠離我。"},
new Product{ Id = 2, Name = "橘子", Description = "醫生給娜美最珍貴的寶藏。"},
new Product{ Id = 3, Name = "梨子", Description = "我是梨子,比蘋果好吃多囉!"},
new Product{ Id = 4, Name = "葡萄", Description = "吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮"},
new Product{ Id = 5, Name = "榴槤", Description = "水果界的珍寶!好吃一直吃。"}
};
}
class Product
{
public long Id { get; set; }
public string Name { get; set; } = null!;
public string Description { get; set; } = null!;
}
List<Product> GetUpdateProductsInformation()
{
return new List<Product>
{
new Product{ Id = 6, Name = "香蕉", Description = "運動完後吃根香蕉補充養分。"},
new Product{ Id = 2, Name = "橘子", Description = "橘子跟柳丁你分得出來嗎?"}
};
}
void Update(string key, List<Product> information, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using( var directory = FSDirectory.Open(dir))
{
using(var indexWriter = new IndexWriter(directory, analyzer, false, IndexWriter.MaxFieldLength.LIMITED))
{
foreach (var index in information)
{
var document = new Document();
document.Add(new Field("Id", index.Id.ToString(), Field.Store.YES, Field.Index.NO));
document.Add(new Field("Name", index.Name, Field.Store.YES, Field.Index.ANALYZED));
document.Add(new Field("Description", index.Description, Field.Store.YES, Field.Index.ANALYZED));
indexWriter.UpdateDocument(new Term("Name", key) ,document);
}
}
}
}
void Delete(string key, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(dir))
{
using (var indexWriter = new IndexWriter(directory, analyzer, false, IndexWriter.MaxFieldLength.LIMITED))
{
indexWriter.DeleteDocuments(new Term("Name", key));
indexWriter.Optimize();
indexWriter.Commit();
}
}
}
void CreateIndexWithBoost(List<Product> information, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(dir))
{
using (var indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED))
{
foreach (var index in information)
{
var document = new Document();
document.Add(new Field("Id", index.Id.ToString(), Field.Store.YES, Field.Index.NO));
document.Add(new Field("Name", index.Name, Field.Store.YES, Field.Index.ANALYZED));
document.Add(new Field("Description", index.Description, Field.Store.YES, Field.Index.ANALYZED));
document.GetField("Name").Boost = 1.5F;
document.GetField("Description").Boost = 0.5F;
indexWriter.AddDocument(document);
}
indexWriter.Optimize();
indexWriter.Commit();
}
}
}
void SearchWithBoost(string searchValue, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(_dir))
{
using (var indexSearcher = new IndexSearcher(directory))
{
var query = new QueryParser(Lucene.Net.Util.Version.LUCENE_CURRENT, "Name", analyzer).Parse(searchValue);
var query2 = new QueryParser(Lucene.Net.Util.Version.LUCENE_CURRENT, "Description", analyzer).Parse(searchValue);
query.Boost = 2.0F;
query2.Boost = 0.5F;
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.Add(query, Occur.SHOULD);
booleanQuery.Add(query2, Occur.SHOULD);
var hits = indexSearcher.Search(booleanQuery, 20);
if (!hits.ScoreDocs.Any())
{
Console.WriteLine("查無相關結果。");
return;
}
Document doc;
foreach (var hit in hits.ScoreDocs)
{
doc = indexSearcher.Doc(hit.Doc);
Console.WriteLine("Score :" + hit.Score + ", Id :" + doc.Get("Id") + ", Name :" + doc.Get("Name") + ", Description :" + doc.Get("Description"));
}
}
}
}