å€ãã®ããã°ã©ããŒã¯ãã¡ã¢ãäœæããå°é£ã説æããèªåã®çŸ©åã®ããã«å¯ŸåŠããªããã°ãªããªãçŸãããŠããã»ã©é£ãããªã決å®ãããŸãã ããã¯ããªãèªèº«ã®æè¡çãªããã°ãåãwikiããŸãã¯éåžžã®ããŒãããã¯ã§ããããããŸã-æ¬è³ªã¯äžã€ã§ãã åŸã ã«ãå°ããªEvernoteãããHabrã®èšäºå šäœãæé·ããå¯èœæ§ããããšææãããŠããŸãã ããããæéãçµã¡ãä»äºã®å€æŽãéçºã¹ã¿ãã¯ã®å€æŽãçŽæããæè¡ã¯ãŸã æ¢ãŸããŸããïŒãšããã§ã ããŒãžã§ã³1.1ã®ããã«ãEF Coreã¯æ°ãæéååšããŠããŸããïŒã äžæ¹ãEntity Framework 6ã¯ãç¹ã«ãã®å®å®æ§ãäœããããå€ãå¹ åºã人æ°ã«ããã.netã¹ã¿ãã¯äžã®äŒæ¥ã¢ããªã±ãŒã·ã§ã³ã®ããŒã¿ã«ã¢ã¯ã»ã¹ããããã®äž»å補åã§ããç¶ããŠããŸãã ãããã£ãŠããã®èšäºããŸã 誰ãã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã
å 容ïŒ
- EDMXãªãã®ããŒã¿ããŒã¹ãã¡ãŒã¹ã
- åæãããã°ã©ããæäœãã
- SQLã®å€æŽã ããŒãã«ã®æ¹åãè¿œå ãã
- DbContextã©ã€ãã¿ã€ã ãã£ãã·ã³ã°
- SQL Serverããã®ãšã©ãŒãåè©Šè¡ãã
- DbContextã眮ãæããå®éã®ããŒã¿ããŒã¹ããåé¢
- ã¯ã€ãã¯æ¿å ¥
EDMXãªãã®ããŒã¿ããŒã¹ãã¡ãŒã¹ã
ãã³ãŒããã¡ãŒã¹ããšããŒã¿ããŒã¹ãã¡ãŒã¹ããã®è°è«ã®æ¬¡ã®ã©ãŠã³ããéå§ããããããŸããã Database Firstã奜ããªããããªãã®äººçããã£ãšæ¥œã«ããæ¹æ³ãæããã»ããããã§ãããã ãã®ã¢ãããŒãã䜿çšããå€ãã®éçºè ã¯ãããã°ãEDMXãã¡ã€ã«ã§äœæ¥ããããšã®äžäŸ¿ãã«æ³šç®ããŠããŸãã ãã®ãã¡ã€ã«ã¯ãããŒã éçºãå°çã«å€ãããã®å éšæ§é ã®çµ¶ãéãªããæ··åãã®ããã«äžŠè¡å€æŽã®ããŒãžãéåžžã«è€éã«ããŸãã æ°çŸã®ãšã³ãã£ãã£ïŒéåžžã®ã¬ã¬ã·ãŒã¢ããªã¹ãªã©ïŒãå«ãã¢ãã«ã§ã¯ãä»ã®æ¬ ç¹ã®äžã§ããæšæºã®EDMXãã¶ã€ããŒã§äœæ¥ããå Žåãã¢ã¯ã·ã§ã³ã®é床ãå€§å¹ ã«äœäžããå ŽåããããŸãã
ãœãªã¥ãŒã·ã§ã³ã¯æãããªããã§ã-POCOãçæããŠã¡ã¿ããŒã¿ãä¿åãã代æ¿æ段ãæ¯æããŠãEDMXãæŸæ£ããå¿ èŠããããŸãã ã¿ã¹ã¯ã¯é£ãããªããEFã«ã¯ãããã«äœ¿çšå¯èœããªãã®ããããŸããããã¯ãVisual Studioã§å©çšå¯èœãªãããŒã¿ããŒã¹ããã³ãŒããæåã«çæãããã¢ã€ãã ã§ãïŒVS2015ïŒã ãã ããå®éã«ã¯ããã®ããŒã«ã䜿çšããŠããŒã¿ããŒã¹ã®å€æŽãçµæã®ã¢ãã«ã«åæ ããããšã¯éåžžã«äžäŸ¿ã§ãã ããã«ãEFã§é·ãéåããŠãã人ã¯ãåæ§ã®åé¡ã解決ããEntity Framework Power Toolsæ¡åŒµæ©èœãèŠããŠãããããããŸããããæ®å¿µãªããããããžã§ã¯ãã¯ããéçºãããŠãããïŒVS2015ãããã¯ããã«ã€ã³ã¹ããŒã«ããããšã¯ã§ããŸããïŒããã®ããŒã«ã®äžéšã®éçºè ã¯EFããŒã ã§çŽæ¥äœæ¥ããŠããŸã
ãã¹ãŠãæªãããã«æããŸããããã§ã EntityFramework Reverse POCO GeneratorãèŠã€ããŸããã ããã¯ãå€æ°ã®èšå®ãšãªãŒãã³ãœãŒã¹ãæã€æ¢åã®ããŒã¿ããŒã¹ã«åºã¥ããŠPOCOãçæããããã®T4ãã³ãã¬ãŒãã§ãã ãã¹ãŠã®äž»èŠãªEDMXæ©èœããµããŒããããŠããããŠããããã¹ãçšã®FakeDbContext / FakeDbSetã®çæãå±æ§ïŒäŸïŒDataContract / DataMemberïŒãªã©ã®ã¢ãã«ã®ã«ããŒãªã©ãå€ãã®è¿œå æ©èœããããŸããT4ã®ãããã§ãã³ãŒãçæãå®å šã«å¶åŸ¡ã§ããŸãã èŠçŽïŒå®å®ããŠåäœããããŒã ã¯æ°ã«å ¥ã£ãŠããŸããæ¢åã®ãããžã§ã¯ããç°¡åã«ç§»è¡ã§ããŸãã
åæãããã°ã©ããæäœãã
éåžžãæ°ããã³ã³ããã¹ããŸãã¯ä»¥åã«ååŸããç°ãªãã³ã³ããã¹ãã®åäžãªããžã§ã¯ããDbContextã«ã¢ã¿ããããããšã¯é£ãããããŸããã åé¡ã¯ãã°ã©ãã®å Žåã«å§ãŸããŸãã ãªã³ã¯ã®ãããšã³ãã£ãã£-EF "out of the box"ã¯ããšã³ãã£ãã£ã®ããã²ãŒã·ã§ã³ããããã£ã®ã³ã³ãã³ãã®å€æŽã远跡ãããã³ã³ããã¹ãã«åçµåããŸãã ã³ã³ããã¹ãã®åç¶æéäžããšã³ãã£ãã£ãªããžã§ã¯ãããšã«å€æŽã远跡ããã«ã¯ã察å¿ãããšã³ããªïŒãšã³ãã£ãã£ã®ç¶æ ïŒè¿œå ãå€æŽãåé€ãªã©ïŒãå«ããµãŒãã¹æ å ±ãæã€ãªããžã§ã¯ãïŒãååšããå¿ èŠããããŸãã ã°ã©ãã«åå ããããã®ãšã³ããªãå ¥åããŸã-å°ãªããšã2ã€ã®æ¹æ³ãå¯èœã§ãã
- ãšã³ãã£ãã£èªäœã«ç¶æ ãä¿åããå€æŽãç¬èªã«è¿œè·¡ããŸãã ãããã£ãŠãåæãããã°ã©ãã«ã¯ãåå ã«å¿ èŠãªãã¹ãŠã®æ å ±ãå«ãŸããŸãã
- äºåã«äœãããã«ãæ°ããã³ã³ããã¹ãã«ã°ã©ããè¿œå ãããšãã«ãããŒã¿ããŒã¹ããå ã®ã°ã©ããåãåºãã2ã€ã®ã°ã©ãã®æ¯èŒã«åºã¥ããŠãšã³ããªç¶æ ãé 眮ããŸãã
ãœãªã¥ãŒã·ã§ã³ïŒ1ã®äŸã¯ãããšãã°ãæåãªEFã¹ãã·ã£ãªã¹ãã§ãããžã¥ãªãŒã©ãŒãã³ã®ææ°ã®Pluralsightã³ãŒã¹ã«ãããŸãã ç¬ç«ããæ±çšå®è£ ã«ã¯ãå€æ°ã®ãžã§ã¹ãã£ãå¿ èŠã§ãã ãã¹ãŠã®ãšã³ãã£ãã£ã¯ãIStateObjectã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããå¿ èŠããããŸãã
public interface IStateObject { ObjectState State { get; set; } }
äœããã®æ¹æ³ã§ãã°ã©ãå ã®åãšã³ãã£ãã£ãã³ã³ããã¹ãã«æåã§æ·»ä»ããåŸãç¶æ å€ã®é¢é£æ§ã確èªããå¿ èŠããããŸãã
context.Foos.Attach(foo);
ãã¹ãŠã®ãšã³ããªã調ã¹ãŠãç¶æ ãç·šéããŸãã
IStateObject entity = entry.Entity; entry.State = ConvertState(entity.State);
ãã®å ŽåãããŒã¿ããŒã¹ãžã®è¿œå ã®åŒã³åºãã¯å¿ èŠãããŸãããããœãªã¥ãŒã·ã§ã³ã¯èšå€§ã§å£ãããããå€å¯Ÿå€ã®é¢ä¿ã§ã¯åäœããªãå¯èœæ§ããããŸãã ã¢ãã«ãæ£ãã°ã£ãŠããŸããïŒãšããã§ãã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£ èŠä»¶ã¯ãèšäºã®åã®ã»ã¯ã·ã§ã³ã®T4ãã³ãã¬ãŒããå€æŽããããšã§è§£æ±ºã§ããŸãïŒã
解決ç2ãæ€èšããŠãã ããã ç°¡åã«èª¬æããŸãã
context.UpdateGraph(root, map => map.OwnedCollection(r => r.Childs));
ãããåŒã³åºã-ã«ãŒããšã³ãã£ãã£ãã³ã³ããã¹ãã«è¿œå ããChildrenåãªããžã§ã¯ãã®ã³ã¬ã¯ã·ã§ã³ã§ããã²ãŒã·ã§ã³ããããã£ãæŽæ°ããŸãããããŒã¿ããŒã¹ãžã®SELECTã®ã¿ã®ã³ã¹ããããããŸãã GraphDiffã©ã€ãã©ãªã®ãããã§å¯èœã«ãªã£ãã®ã¯ãäœè ããã¹ãŠã®æ±ãä»äºãããäž»èŠãªãã°ããã£ããããããã§ãã
SQLã®å€æŽã ããŒãã«ã®æ¹åãè¿œå ãã
äžèŠåçŽãªSELECT ... FROM Table WITHïŒUPDLOCKïŒã¹ããŒãã¡ã³ãã®çæã¯ãEFã§ã¯ãµããŒããããŠããŸããã ãã ããããšãã°æ£èŠè¡šçŸã䜿çšãããªã©ãé©åãªæ¹æ³ã§çæãããSQLãå€æŽã§ããã€ã³ã¿ãŒã»ãã¿ãŒããããŸãã ã³ã³ããã¹ãã®æå¹æéå ã«çæãããåSELECTã«UPDLOCKãè¿œå ããŸãããïŒåœç¶ãç²åºŠã¯å¿ ãããã³ã³ããã¹ãã§ã¯ãªãããã¹ãŠå®è£ ã«äŸåããŸãïŒã
using (var ctx = new MyDbContext().With(SqlLockMode.UpdLock)) {}
ãããè¡ãã«ã¯ãã³ã³ããã¹ãå ã§Withã¡ãœããã宣èšããã€ã³ã¿ãŒã»ãã¿ãŒãç»é²ããŸãã
public interface ILockContext { SqlLockMode LockMode { get; set; } MyDbContext With(SqlLockMode lockMode); } public class MyDbConfig : DbConfiguration { public MyDbConfig() { AddInterceptor(new LockInterceptor()); } } [DbConfigurationType(typeof(MyDbConfig))] public partial class MyDbContext : ILockContext { public SqlLockMode LockMode { get; set; } public MyDbContext With(SqlLockMode lockMode) { LockMode = lockMode; return this; } private static void MyDbContextStaticPartial() { } }
public class LockInterceptor : DbCommandInterceptor { public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { AddLockStatement(command, interceptionContext); } public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { AddLockStatement(command, interceptionContext); } private void AddLockStatement<T>(DbCommand command, DbCommandInterceptionContext<T> interceptionContext) { var lockMode = GetLock(interceptionContext); switch (lockMode) { case SqlLockMode.UpdLock: command.CommandText = SqlModifier.AddUpdLock(command.CommandText); break; } } private SqlLockMode GetLock<T>(DbCommandInterceptionContext<T> interceptionContext) { if (interceptionContext == null) return SqlLockMode.None; ILockContext lockContext = interceptionContext.DbContexts.First() as ILockContext; if (lockContext == null) return SqlLockMode.None; return lockContext.LockMode; } }
public static class SqlModifier { private static readonly Regex _regex = new Regex(@"(?<tableAlias>SELECT\s.*FROM\s.*AS \[Extent\d+])", RegexOptions.Multiline | RegexOptions.IgnoreCase); public static string AddUpdLock(string text) { return _regex.Replace(text, "${tableAlias} WITH (UPDLOCK)"); } }
public class SqlModifier_Tests { [TestCase("SELECT [Extent1].[Name] AS [Name] FROM [dbo].[Customer] AS [Extent1]")] [TestCase("SELECT * FROM [dbo].[Customer] AS [Extent999]")] public void AddUpdLock_ValidEfSelectStatement_AddLockAfterTableAlias(string text) { string expected = text + " WITH (UPDLOCK)"; string actual = SqlModifier.AddUpdLock(text); Assert.AreEqual(expected, actual); } [TestCase("SELECT [Extent1].[Extent1] AS [Extent1]")] [TestCase("SELECT * FROM Order")] [TestCase(" AS [Extent111]")] public void AddUpdLock_InvalidEfSelectStatement_NoChange(string text) { string actual = SqlModifier.AddUpdLock(text); Assert.AreEqual(text, actual); } }
DbContextã©ã€ãã¿ã€ã ãã£ãã·ã³ã°
EFã¯æ¬¡ã®ãããªãã®ããã£ãã·ã¥ããŸãã
- ã¯ãšãªãã©ã³ã
- ã¡ã¿ããŒã¿ã
- ã³ã³ãã€ã«ãããã¯ãšãªã
ããŒã¿ã®ãã£ãã·ã³ã°ã¯äººçã®ã³ã³ããã¹ãå ã§ã®ã¿è¡ããïŒFindã¡ãœãããæãåºããŠãã ããïŒããã®èšèªãæ¬æ Œçãªãã£ãã·ã¥ãšåŒã¶ããšã¯ã§ããŸããã ããã»ã¹ã¡ã¢ãªå ã®ãã¹ãŠã®ã³ã³ããã¹ããã£ãã·ã¥çšã«å¶åŸ¡ãããçµ±äžããããã£ãã·ã¥ãã©ã®ããã«æŽçããŸããïŒ EntityFramework.PlusãŸãã¯ãã®ã貧匱ãªã代æ¿EntityFramework.Cacheã䜿çšããŸãã
public void SelectWithCache() { using (var ctx = new MyDbContext()) { ctx.Customers.FromCache().ToList(); } } [Test] public void SelectWithCache_Test() { TimeSpan expiration = TimeSpan.FromSeconds(5); var options = new CacheItemPolicy() { SlidingExpiration = expiration }; QueryCacheManager.DefaultCacheItemPolicy = options; SelectWithCache(); // SelectWithCache(); // Thread.Sleep(expiration); SelectWithCache(); // }
SelectWithCacheïŒïŒã®2åç®ã®åŒã³åºããããŒã¿ããŒã¹ã«åœ±é¿ããªãããšã確èªããã«ã¯ãSQLãããã¡ã€ã©ãŒãå®è¡ããã ãã§ååã§ãã é 延ãããããã£ãã·ã¥ãããŸãã
ããã«ãEFãšåæ£ãã£ãã·ã¥ã®çµ±åãå¯èœã§ãã ããšãã°ãEntityFramework.Plusã«æ¥ç¶ãããSytem.Runtime.Caching.ObjectCacheã«åºã¥ãèªå·±èšè¿°åã®ãã£ãã·ã¥ãããŒãžã£ãŒã䜿çšããŸãã NCache 㯠ãããã«äœ¿çšã§ããEFãšã®çµ±åããµããŒãããŠããŸãïŒè©³çŽ°ãå ±æã§ããŸãã-ãã®ãã£ãã·ã¥ã¯è©ŠããŠããŸããïŒã
SQL Serverããã®ãšã©ãŒãåè©Šè¡ãã
public class SchoolConfiguration : DbConfiguration { public SchoolConfiguration() { SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy(maxRetryCount: 3, maxDelay: TimeSpan.FromSeconds(10))); } }
SqlAzureExecutionStrategy-ãã®æŠç¥ã¯EF6ã«å«ãŸããŠããŸãïŒæ¢å®ã§ã¯ç¡å¹ïŒã 䜿çšããå ŽåãSQL Serverããã®å¿çã§ç¹å®ã®ãšã©ãŒã³ãŒããåä¿¡ãããšããµãŒããŒã«SQLã¹ããŒãã¡ã³ããç¹°ãè¿ãéä¿¡ãããŸãã
// SQL Error Code: 40197 // The service has encountered an error processing your request. Please try again. case 40197: // SQL Error Code: 40501 // The service is currently busy. Retry the request after 10 seconds. case 40501: // SQL Error Code: 10053 // A transport-level error has occurred when receiving results from the server. // An established connection was aborted by the software in your host machine. case 10053: // SQL Error Code: 10054 // A transport-level error has occurred when sending the request to the server. // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) case 10054: // SQL Error Code: 10060 // A network-related or instance-specific error occurred while establishing a connection to SQL Server. // The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server // is configured to allow remote connections. (provider: TCP Provider, error: 0 - A connection attempt failed // because the connected party did not properly respond after a period of time, or established connection failed // because connected host has failed to respond.)"} case 10060: // SQL Error Code: 40613 // Database XXXX on server YYYY is not currently available. Please retry the connection later. If the problem persists, contact customer // support, and provide them the session tracing ID of ZZZZZ. case 40613: // SQL Error Code: 40143 // The service has encountered an error processing your request. Please try again. case 40143: // SQL Error Code: 233 // The client was unable to establish a connection because of an error during connection initialization process before login. // Possible causes include the following: the client tried to connect to an unsupported version of SQL Server; the server was too busy // to accept new connections; or there was a resource limitation (insufficient memory or maximum allowed connections) on the server. // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) case 233: // SQL Error Code: 64 // A connection was successfully established with the server, but then an error occurred during the login process. // (provider: TCP Provider, error: 0 - The specified network name is no longer available.) case 64: // DBNETLIB Error Code: 20 // The instance of SQL Server you attempted to connect to does not support encryption. case (int)ProcessNetLibErrorCode.EncryptionNotSupported: return true;
èå³ïŒ
- SqlAzureExecutionStrategyãœãŒã¹ã³ãŒãã«åºã¥ããŠãåè©Šè¡ã«ã€ãªãããšã©ãŒã³ãŒãããªãŒããŒã©ã€ãããããšã«ãããç¬èªã®æŠç¥ãèšè¿°ããããšãã§ããŸãã
- SqlAzureExecutionStrategyãå«ãåè©Šè¡æŠç¥ã䜿çšãããšãå€ãã®å¶éã課ããããŸãããæãæ·±å»ãªã®ã¯ãŠãŒã¶ãŒãã©ã³ã¶ã¯ã·ã§ã³ãšã®éäºææ§ã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ãæ瀺çã«å®£èšããã«ã¯ã System.Runtime.Remoting.Messaging.CallContextãåŒã³åºããŠæŠç¥ãç¡å¹ã«ããŸã ã
- çµ±åãã¹ãã§æŠç¥ã説æããããšãã§ããŸãïŒãã®åé¡ã«ã€ããŠè©³ãã説æããŠãããJulie Lermanã«æè¬ããŸã ïŒã
DbContextã眮ãæããå®éã®ããŒã¿ããŒã¹ããåé¢
ãã¹ãã®ããã«ãåŒã³åºãã³ãŒãã®DbContextãééçã«çœ®ãæããåœã®DbSetã«ãã¹ãããŒã¿ãå
¥åããŸãã åé¡ã解決ããæ¹æ³ãããã€ã玹ä»ããŸãã
æ¹æ³ïŒ1 ïŒé·ãïŒïŒIMyDbContextããã³DbSetã®ã¹ã¿ããæåã§äœæããå¿
èŠãªåäœãæ瀺çã«æå®ããŸãã Moqã©ã€ãã©ãªã䜿çšãããšã次ã®ããã«ãªããŸãã
public IMyDbContext Create() { var mockRepository = new MockRepository(MockBehavior.Default); var mockContext = mockRepository.Create<IMyDbContext>(); mockContext.Setup(x => x.SaveChanges()).Returns(int.MaxValue); var mockDbSet = MockDbSet<Customer>(customers); mockContext.Setup(m => m.Customers).Returns(mockDbSet.Object); return mockContext.Object; } private Mock<DbSet<T>> MockDbSet<T>(List<T> data = null) where T : class { if (data == null) data = new List<T>(); var queryable = data.AsQueryable(); var mock = new Mock<DbSet<T>>(); mock.As<IQueryable<T>>().Setup(m => m.Provider) .Returns(queryable.Provider); mock.As<IQueryable<T>>().Setup(m => m.Expression) .Returns(queryable.Expression); mock.As<IQueryable<T>>().Setup(m => m.ElementType) .Returns(queryable.ElementType); mock.As<IQueryable<T>>().Setup(m => m.GetEnumerator()) .Returns(queryable.GetEnumerator()); return mock; }
MSDNã«é¢ãããã®ãããã¯ã«é¢ããåºæ¬çãªèšäºããããŸãïŒ ã¢ãã¯ãã¬ãŒã ã¯ãŒã¯ã䜿çšããEntity Framework TestingïŒEF6以éïŒ ã ãããŠããã®ã¢ãããŒãã¯ãã€ãŠéåžžã«å°è±¡çã§ãgithubã§ãã¢ãããžã§ã¯ããååŸããŸããïŒEF6 DbFirstãSQL ServerãMoqãNinjectã䜿çšïŒã ã¡ãªã¿ã«ã ãšã³ã¿ãŒãã©ã€ãºã³ãŒã¹ã§æ¢ã«èª¬æããEntity Frameworkã®ãã¹ãã«ã€ããŠã¯ãç« å šäœã§èª¬æããŸãã
æ¹æ³ïŒ2 ïŒçãïŒïŒæ¢ã«èª¬æããReverse POCO Generatorã䜿çšããŸããããã¯ãããã©ã«ãã§DbContextããã³ãã¹ãŠã®DbSetã®ã¹ã¿ããäœæããŸãïŒFakeDbSetå
ã«ã¯éåžžã®ã¡ã¢ãªå
ã³ã¬ã¯ã·ã§ã³ããããŸãïŒã
ã¯ã€ãã¯æ¿å ¥
æ°åã®æ°ããã¬ã³ãŒããSQL ServerããŒã¿ããŒã¹ã«åæã«æ¿å ¥ããã«ã¯ãæšæºã®è¡ããšã®INSERTã®ä»£ããã«BULKæäœã䜿çšããã®ãéåžžã«å¹ççã§ãã ãã®åé¡ã«ã€ããŠã¯å¥ã®èšäºã§è©³ãã説æããŸããããããã£ãŠã以äžã§ã¯SqlBulkCopyã«åºã¥ãããã«äœ¿çšã§ãããœãªã¥ãŒã·ã§ã³ã®ã¿ãæäŸããŸãã
â EntityFramework.Utilities
â ãšã³ãã£ãã£ãã¬ãŒã ã¯ãŒã¯æ¡åŒµ
ããã ãã§ãã ã³ã¡ã³ãã§ã¬ã·ããã³ããå ±æããŠãã ãã=ïŒ