在 EF Core 中执行存储过程,从 JOIN 返回 int。 blazor(客户端)

Execute stored procedure in EF Core returning int from JOIN. blazor(client-side)

如何在 EF Core 中获取从 SQL Server 中的存储过程返回的 int 值?

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

在 SQL Server 测试中返回正确的 Employee.Id

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

现在在 Blazor(客户端)控制器中,我正在尝试执行存储过程。

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

我得到了这个例外:

FromSqlRaw or FromSqlInterpolated was called with non-composable SQL and with a query composing over it.

Consider calling AsEnumerable after the FromSqlRaw or FromSqlInterpolated method to perform the composition on the client side.

如果尝试

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

它总是返回-1,因为没有行受到影响。

我看到了很多东西,但没有成功...在此先感谢

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);
  • https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/break-changes#linq-queries-are-no-longer-evaluated-on-the-客户
  • https://github.com/dotnet/efcore/issues/17558
  • 在 EF Core 3.1 中包含 FromSqlRaw 和存储过程
  • 如何通过 FromSqlRaw 在 EF Core 3.0 中调用存储过程
  • EF core 3.1 无法运行复杂的原始 sql 查询
  • https://www.sqlservertutorial.net/sql-server-stored-procedures/stored-procedure-output-parameters/

您有不可组合的 SQL。关键是实体框架会写类似

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

它这样做是为了确定能够实现(嵌套)结果、分页等的格式。

如果你没有从你的存储过程中选择任何东西,它就不能组成这个查询。它无论如何都不会返回结果集,因此您也无法从 dbContext.Employee 中进行选择。那将是两个不同的查询。一个获取您已经拥有的 ID:

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

这确实返回 -1,因为您的查询中有错误。您提供了一个名为 @count 的参数,但提供了一个名为 @idemp.

的已配置参数

所以请确保你正确地传递参数:

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

然后使用ID参数查询:

--Two tables, Employee and AspNetUsers--

CREATE PROCEDURE SP_GetIdEmployeeByUserName

  (@username varchar(100), @idemployee int output)

AS

BEGIN

  SELECT @idemployee = (SELECT e.Id 

             FROM Employee e

             JOIN AspNetUsers a ON e.IdUser = a.Id

             WHERE a.Email = @username)



END



--Executing in database--

DECLARE @idemp INT;

EXEC SP_GetIdEmployeeByUserName 'someinsertedemail@gmail.com', @idemp output

SELECT @idemp;
idemp `Id = 40`
[HttpGet]

[Route("getbyname")]

public int GetByName([FromQuery] string username)

{

    try

    {

      if (!string.IsNullOrEmpty(username))

      {

        SqlParameter paramUsername = new SqlParameter("@username", username);



        var paramOut = new SqlParameter

        {

          ParameterName ="@idemp",

          SqlDbType = System.Data.SqlDbType.Int,

          Direction = System.Data.ParameterDirection.Output,

        };



        var result = _context

          .Employee.FromSqlRaw

          ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut)

          .FirstOrDefault();



        Console.WriteLine("result = >>>>>>>>>" + result);



        return result.Id;

      }

      else

      {

        return 0;

      }



    }

    catch (Exception ex)

    {

      Console.WriteLine("ex ->" + ex);

      throw;

    }

  }

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);
_context.Database.ExecuteSqlCommand if obsolete
SELECT [Generated Column Names] FROM 

(

  @YOURQUERY

)

var result = _context

      .Database.ExecuteSqlRaw

      ($"EXEC SP_GetIdFuncByUserName @username, @count OUTPUT", paramUsername, paramOut);

var result = _context

        .Database.ExecuteSqlRaw

        ($"EXEC SP_GetIdFuncByUserName @username, @idemp OUTPUT", paramUsername, paramOut);

var employeeId = paramOut.Value;

var employee = _context.Employee.FirstOrDefault(e => e.Id == employeeId);

相关推荐

  • Spring部署设置openshift

    Springdeploymentsettingsopenshift我有一个问题让我抓狂了三天。我根据OpenShift帐户上的教程部署了spring-eap6-quickstart代码。我已配置调试选项,并且已将Eclipse工作区与OpehShift服务器同步-服务器上的一切工作正常,但在Eclipse中出现无法消除的错误。我有这个错误:cvc-complex-type.2.4.a:Invali…
    2025-04-161
  • 检查Java中正则表达式中模式的第n次出现

    CheckfornthoccurrenceofpatterninregularexpressioninJava本问题已经有最佳答案,请猛点这里访问。我想使用Java正则表达式检查输入字符串中特定模式的第n次出现。你能建议怎么做吗?这应该可以工作:MatchResultfindNthOccurance(intn,Patternp,CharSequencesrc){Matcherm=p.matcher…
    2025-04-161
  • 如何让 JTable 停留在已编辑的单元格上

    HowtohaveJTablestayingontheeditedcell如果有人编辑JTable的单元格内容并按Enter,则内容会被修改并且表格选择会移动到下一行。是否可以禁止JTable在单元格编辑后转到下一行?原因是我的程序使用ListSelectionListener在单元格选择上同步了其他一些小部件,并且我不想在编辑当前单元格后选择下一行。Enter的默认绑定是名为selectNext…
    2025-04-161
  • Weblogic 12c 部署

    Weblogic12cdeploy我正在尝试将我的应用程序从Tomcat迁移到Weblogic12.2.1.3.0。我能够毫无错误地部署应用程序,但我遇到了与持久性提供程序相关的运行时错误。这是堆栈跟踪:javax.validation.ValidationException:CalltoTraversableResolver.isReachable()threwanexceptionatorg.…
    2025-04-161
  • Resteasy Content-Type 默认值

    ResteasyContent-Typedefaults我正在使用Resteasy编写一个可以返回JSON和XML的应用程序,但可以选择默认为XML。这是我的方法:@GET@Path("/content")@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})publicStringcontentListRequestXm…
    2025-04-161
  • 代码不会停止运行,在 Java 中

    thecodedoesn'tstoprunning,inJava我正在用Java解决项目Euler中的问题10,即"Thesumoftheprimesbelow10is2+3+5+7=17.Findthesumofalltheprimesbelowtwomillion."我的代码是packageprojecteuler_1;importjava.math.BigInteger;importjava…
    2025-04-161
  • Out of memory java heap space

    Outofmemoryjavaheapspace我正在尝试将大量文件从服务器发送到多个客户端。当我尝试发送大小为700mb的文件时,它显示了"OutOfMemoryjavaheapspace"错误。我正在使用Netbeans7.1.2版本。我还在属性中尝试了VMoption。但仍然发生同样的错误。我认为阅读整个文件存在一些问题。下面的代码最多可用于300mb。请给我一些建议。提前致谢publicc…
    2025-04-161
  • Log4j 记录到共享日志文件

    Log4jLoggingtoaSharedLogFile有没有办法将log4j日志记录事件写入也被其他应用程序写入的日志文件。其他应用程序可以是非Java应用程序。有什么缺点?锁定问题?格式化?Log4j有一个SocketAppender,它将向服务发送事件,您可以自己实现或使用与Log4j捆绑的简单实现。它还支持syslogd和Windows事件日志,这对于尝试将日志输出与来自非Java应用程序…
    2025-04-161